home *** CD-ROM | disk | FTP | other *** search
/ Openstep 4.2 (Developer) / Openstep Developer 4.2.iso / NextDeveloper / Source / GNU / uucp / Uucp.framework / unix.subproj / serial.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-11-02  |  82.5 KB  |  3,403 lines

  1. /* serial.c
  2.    The serial port communication routines for Unix.
  3.  
  4.    Copyright (C) 1991, 1992, 1993, 1994, 1995 Ian Lance Taylor
  5.  
  6.    This file is part of the Taylor UUCP package.
  7.  
  8.    This program is free software; you can redistribute it and/or
  9.    modify it under the terms of the GNU General Public License as
  10.    published by the Free Software Foundation; either version 2 of the
  11.    License, or (at your option) any later version.
  12.  
  13.    This program is distributed in the hope that it will be useful, but
  14.    WITHOUT ANY WARRANTY; without even the implied warranty of
  15.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16.    General Public License for more details.
  17.  
  18.    You should have received a copy of the GNU General Public License
  19.    along with this program; if not, write to the Free Software
  20.    Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  21.  
  22.    The author of the program may be contacted at ian@airs.com or
  23.    c/o Cygnus Support, 48 Grove Street, Somerville, MA 02144.
  24.    */
  25.  
  26. #include "uucp.h"
  27.  
  28. #if USE_RCS_ID
  29. const char serial_rcsid[] = "$Id: serial.c,v 1.65 1995/08/10 00:53:54 ian Rel $";
  30. #endif
  31.  
  32. #include "uudefs.h"
  33. #include "uuconf.h"
  34. #include "system.h"
  35. #include "conn.h"
  36. #include "sysdep.h"
  37.  
  38. #include <errno.h>
  39. #include <ctype.h>
  40.  
  41. #if HAVE_SYS_PARAM_H
  42. #include <sys/param.h>
  43. #endif
  44.  
  45. #if HAVE_LIMITS_H
  46. #include <limits.h>
  47. #endif
  48.  
  49. #if HAVE_TLI
  50. #if HAVE_TIUSER_H
  51. #include <tiuser.h>
  52. #else /* ! HAVE_TIUSER_H */
  53. #if HAVE_XTI_H
  54. #include <xti.h>
  55. #endif /* HAVE_XTI_H */
  56. #endif /* ! HAVE_TIUSER_H */
  57. #endif /* HAVE_TLI */
  58.  
  59. #if HAVE_FCNTL_H
  60. #include <fcntl.h>
  61. #else
  62. #if HAVE_SYS_FILE_H
  63. #include <sys/file.h>
  64. #endif
  65. #endif
  66.  
  67. #ifndef O_RDONLY
  68. #define O_RDONLY 0
  69. #define O_WRONLY 1
  70. #define O_RDWR 2
  71. #endif
  72.  
  73. #ifndef O_NOCTTY
  74. #define O_NOCTTY 0
  75. #endif
  76.  
  77. #ifndef FD_CLOEXEC
  78. #define FD_CLOEXEC 1
  79. #endif
  80.  
  81. #if HAVE_SYS_IOCTL_H || HAVE_TXADDCD
  82. #include <sys/ioctl.h>
  83. #endif
  84.  
  85. #if HAVE_SELECT
  86. #if HAVE_SYS_TIME_H
  87. #include <sys/time.h>
  88. #endif
  89. #if HAVE_SYS_SELECT_H
  90. #include <sys/select.h>
  91. #endif
  92. #endif
  93.  
  94. #if HAVE_TIME_H
  95. #if ! HAVE_SYS_TIME_H || ! HAVE_SELECT || TIME_WITH_SYS_TIME
  96. #include <time.h>
  97. #endif
  98. #endif
  99.  
  100. #if HAVE_STRIP_BUG && HAVE_BSD_TTY
  101. #include <termio.h>
  102. #endif
  103.  
  104. #if HAVE_SVR4_LOCKFILES
  105. /* Get the right definitions for major and minor.  */
  106. #if MAJOR_IN_MKDEV
  107. #include <sys/mkdev.h>
  108. #endif /* MAJOR_IN_MKDEV */
  109. #if MAJOR_IN_SYSMACROS
  110. #include <sys/sysmacros.h>
  111. #endif /* MAJOR_IN_SYSMACROS */
  112. #if ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS
  113. #ifndef major
  114. #define major(i) (((i) >> 8) & 0xff)
  115. #endif
  116. #ifndef minor
  117. #define minor(i) ((i) & 0xff)
  118. #endif
  119. #endif /* ! MAJOR_IN_MKDEV && ! MAJOR_IN_SYSMACROS */
  120. #endif /* HAVE_SVR4_LOCKFILES */
  121.  
  122. #if HAVE_DEV_INFO
  123. #include <sys/dev.h>
  124. #endif
  125.  
  126. /* Get definitions for both O_NONBLOCK and O_NDELAY.  */
  127. #ifndef O_NDELAY
  128. #ifdef FNDELAY
  129. #define O_NDELAY FNDELAY
  130. #else /* ! defined (FNDELAY) */
  131. #define O_NDELAY 0
  132. #endif /* ! defined (FNDELAY) */
  133. #endif /* ! defined (O_NDELAY) */
  134.  
  135. #ifndef O_NONBLOCK
  136. #ifdef FNBLOCK
  137. #define O_NONBLOCK FNBLOCK
  138. #else /* ! defined (FNBLOCK) */
  139. #define O_NONBLOCK 0
  140. #endif /* ! defined (FNBLOCK) */
  141. #endif /* ! defined (O_NONBLOCK) */
  142.  
  143. #if O_NDELAY == 0 && O_NONBLOCK == 0
  144.  #error No way to do nonblocking I/O
  145. #endif
  146.  
  147. /* Get definitions for EAGAIN, EWOULDBLOCK and ENODATA.  */
  148. #ifndef EAGAIN
  149. #ifndef EWOULDBLOCK
  150. #define EAGAIN (-1)
  151. #define EWOULDBLOCK (-1)
  152. #else /* defined (EWOULDBLOCK) */
  153. #define EAGAIN EWOULDBLOCK
  154. #endif /* defined (EWOULDBLOCK) */
  155. #else /* defined (EAGAIN) */
  156. #ifndef EWOULDBLOCK
  157. #define EWOULDBLOCK EAGAIN
  158. #endif /* ! defined (EWOULDBLOCK) */
  159. #endif /* defined (EAGAIN) */
  160.  
  161. #ifndef ENODATA
  162. #define ENODATA EAGAIN
  163. #endif
  164.  
  165. /* Make sure we have a definition for MAX_INPUT.  */
  166. #ifndef MAX_INPUT
  167. #define MAX_INPUT (256)
  168. #endif
  169.  
  170. /* If we have the TIOCSINUSE ioctl call, we use it to lock a terminal.
  171.    Otherwise, if we have the TIOCEXCL ioctl call, we have to open the
  172.    terminal before we know that it is unlocked.  */
  173. #ifdef TIOCSINUSE
  174. #define HAVE_TIOCSINUSE 1
  175. #else
  176. #ifdef TIOCEXCL
  177. #define HAVE_TIOCEXCL 1
  178. #endif
  179. #endif
  180.  
  181. #if HAVE_TLI
  182. extern int t_errno;
  183. extern char *t_errlist[];
  184. extern int t_nerr;
  185. #endif
  186.  
  187. /* Determine bits to clear for the various terminal control fields for
  188.    HAVE_SYSV_TERMIO and HAVE_POSIX_TERMIOS.  */
  189.  
  190. /* These fields are defined on some systems, and I am told that it
  191.    does not hurt to clear them, and it sometimes helps.  */
  192. #ifndef IMAXBEL
  193. #define IMAXBEL 0
  194. #endif
  195.  
  196. #ifndef PENDIN
  197. #define PENDIN 0
  198. #endif
  199.  
  200. #if HAVE_SYSV_TERMIO
  201. #define ICLEAR_IFLAG (IGNBRK | BRKINT | IGNPAR | PARMRK | INPCK \
  202.               | ISTRIP | INLCR | IGNCR | ICRNL | IUCLC \
  203.               | IXON | IXANY | IXOFF | IMAXBEL)
  204. #define ICLEAR_OFLAG (OPOST | OLCUC | ONLCR | OCRNL | ONOCR | ONLRET \
  205.               | OFILL | OFDEL | NLDLY | CRDLY | TABDLY | BSDLY \
  206.               | VTDLY | FFDLY)
  207. #define ICLEAR_CFLAG (CBAUD | CSIZE | PARENB | PARODD)
  208. #define ISET_CFLAG (CS8 | CREAD | HUPCL)
  209. #define ICLEAR_LFLAG (ISIG | ICANON | XCASE | ECHO | ECHOE | ECHOK \
  210.               | ECHONL | NOFLSH | PENDIN)
  211. #endif
  212. #if HAVE_POSIX_TERMIOS
  213. #define ICLEAR_IFLAG (BRKINT | ICRNL | IGNBRK | IGNCR | IGNPAR \
  214.               | INLCR | INPCK | ISTRIP | IXOFF | IXON \
  215.               | PARMRK | IMAXBEL)
  216. #define ICLEAR_OFLAG (OPOST)
  217. #define ICLEAR_CFLAG (CSIZE | PARENB | PARODD)
  218. #define ISET_CFLAG (CS8 | CREAD | HUPCL)
  219. #define ICLEAR_LFLAG (ECHO | ECHOE | ECHOK | ECHONL | ICANON | IEXTEN \
  220.               | ISIG | NOFLSH | TOSTOP | PENDIN)
  221. #endif
  222.  
  223. enum tclocal_setting
  224. {
  225.   SET_CLOCAL,
  226.   CLEAR_CLOCAL,
  227.   IGNORE_CLOCAL
  228. };
  229.  
  230. /* Local functions.  */
  231.  
  232. static RETSIGTYPE usalarm P((int isig));
  233. static boolean fsserial_init P((struct sconnection *qconn,
  234.                 const struct sconncmds *qcmds,
  235.                 const char *zdevice));
  236. static void usserial_free P((struct sconnection *qconn));
  237. static boolean fsserial_lockfile P((boolean flok,
  238.                     const struct sconnection *));
  239. static boolean fsserial_lock P((struct sconnection *qconn,
  240.                 boolean fin));
  241. static boolean fsserial_unlock P((struct sconnection *qconn));
  242. static boolean fsserial_open P((struct sconnection *qconn, long ibaud,
  243.                 boolean fwait, enum tclocal_setting tlocal));
  244. static boolean fsstdin_open P((struct sconnection *qconn, long ibaud,
  245.                    boolean fwait));
  246. static boolean fsmodem_open P((struct sconnection *qconn, long ibaud,
  247.                    boolean fwait));
  248. static boolean fsdirect_open P((struct sconnection *qconn, long ibaud,
  249.                 boolean fwait));
  250. static boolean fsblock P((struct ssysdep_conn *q, boolean fblock));
  251. static boolean fsserial_close P((struct ssysdep_conn *q));
  252. static boolean fsstdin_close P((struct sconnection *qconn,
  253.                 pointer puuconf,
  254.                 struct uuconf_dialer *qdialer,
  255.                 boolean fsuccess));
  256. static boolean fsmodem_close P((struct sconnection *qconn,
  257.                 pointer puuconf,
  258.                 struct uuconf_dialer *qdialer,
  259.                 boolean fsuccess));
  260. static boolean fsdirect_close P((struct sconnection *qconn,
  261.                  pointer puuconf,
  262.                  struct uuconf_dialer *qdialer,
  263.                  boolean fsuccess));
  264. static boolean fsserial_break P((struct sconnection *qconn));
  265. static boolean fsstdin_break P((struct sconnection *qconn));
  266. static boolean fsserial_set P((struct sconnection *qconn,
  267.                    enum tparitysetting tparity,
  268.                    enum tstripsetting tstrip,
  269.                    enum txonxoffsetting txonxoff));
  270. static boolean fsstdin_set P((struct sconnection *qconn,
  271.                    enum tparitysetting tparity,
  272.                    enum tstripsetting tstrip,
  273.                    enum txonxoffsetting txonxoff));
  274. static boolean fsmodem_carrier P((struct sconnection *qconn,
  275.                   boolean fcarrier));
  276. static boolean fsserial_hardflow P((struct sconnection *qconn,
  277.                     boolean fhardflow));
  278. static boolean fsrun_chat P((int oread, int owrite, char **pzprog));
  279. static long isserial_baud P((struct sconnection *qconn));
  280.  
  281. /* The command table for standard input ports.  */
  282.  
  283. static const struct sconncmds sstdincmds =
  284. {
  285.   usserial_free,
  286.   NULL, /* pflock */
  287.   NULL, /* pfunlock */
  288.   fsstdin_open,
  289.   fsstdin_close,
  290.   NULL, /* pfdial */
  291.   fsdouble_read,
  292.   fsdouble_write,
  293.   fsysdep_conn_io,
  294.   fsstdin_break,
  295.   fsstdin_set,
  296.   NULL, /* pfcarrier */
  297.   fsdouble_chat,
  298.   isserial_baud
  299. };
  300.  
  301. /* The command table for modem ports.  */
  302.  
  303. static const struct sconncmds smodemcmds =
  304. {
  305.   usserial_free,
  306.   fsserial_lock,
  307.   fsserial_unlock,
  308.   fsmodem_open,
  309.   fsmodem_close,
  310.   fmodem_dial,
  311.   fsysdep_conn_read,
  312.   fsysdep_conn_write,
  313.   fsysdep_conn_io,
  314.   fsserial_break,
  315.   fsserial_set,
  316.   fsmodem_carrier,
  317.   fsysdep_conn_chat,
  318.   isserial_baud
  319. };
  320.  
  321. /* The command table for direct ports.  */
  322.  
  323. static const struct sconncmds sdirectcmds =
  324. {
  325.   usserial_free,
  326.   fsserial_lock,
  327.   fsserial_unlock,
  328.   fsdirect_open,
  329.   fsdirect_close,
  330.   NULL, /* pfdial */
  331.   fsysdep_conn_read,
  332.   fsysdep_conn_write,
  333.   fsysdep_conn_io,
  334.   fsserial_break,
  335.   fsserial_set,
  336.   NULL, /* pfcarrier */
  337.   fsysdep_conn_chat,
  338.   isserial_baud
  339. };
  340.  
  341. /* If the system will let us set both O_NDELAY and O_NONBLOCK, we do
  342.    so.  This is because some ancient drivers on some systems appear to
  343.    look for one but not the other.  Some other systems will give an
  344.    EINVAL error if we attempt to set both, so we use a static global
  345.    to hold the value we want to set.  If we get EINVAL, we change the
  346.    global and try again (if some system gives an error other than
  347.    EINVAL, the code will have to be modified).  */
  348. static int iSunblock = O_NDELAY | O_NONBLOCK;
  349.  
  350. /* This code handles SIGALRM.  See the discussion above
  351.    fsysdep_conn_read.  Normally we ignore SIGALRM, but the handler
  352.    will temporarily be set to this function, which should set fSalarm
  353.    and then either longjmp or schedule another SIGALRM.  fSalarm is
  354.    never referred to outside of this file, but we don't make it static
  355.    to try to fool compilers which don't understand volatile.  */
  356.  
  357. volatile sig_atomic_t fSalarm;
  358.  
  359. static RETSIGTYPE
  360. usalarm (isig)
  361.      int isig;
  362. {
  363. #if ! HAVE_SIGACTION && ! HAVE_SIGVEC && ! HAVE_SIGSET
  364.   (void) signal (isig, usalarm);
  365. #endif
  366.  
  367.   fSalarm = TRUE;
  368.  
  369. #if HAVE_RESTARTABLE_SYSCALLS
  370.   longjmp (sSjmp_buf, 1);
  371. #else
  372.   alarm (1);
  373. #endif
  374. }
  375.  
  376. /* We need a simple routine to block SIGINT, SIGQUIT, SIGTERM and
  377.    SIGPIPE and another to restore the original state.  When these
  378.    functions are called (in fsysdep_modem_close) SIGHUP is being
  379.    ignored.  The routines are isblocksigs, which returns a value of
  380.    type HELD_SIG_MASK and usunblocksigs which takes a single argument
  381.    of type HELD_SIG_MASK.  */
  382.  
  383. #if HAVE_SIGPROCMASK
  384.  
  385. /* Use the POSIX sigprocmask call.  */
  386.  
  387. #define HELD_SIG_MASK sigset_t
  388.  
  389. static sigset_t isblocksigs P((void));
  390.  
  391. static sigset_t
  392. isblocksigs ()
  393. {
  394.   sigset_t sblock, sold;
  395.  
  396.   /* These expressions need an extra set of parentheses to avoid a bug
  397.      in SCO 3.2.2.  */
  398.   (void) (sigemptyset (&sblock));
  399.   (void) (sigaddset (&sblock, SIGINT));
  400.   (void) (sigaddset (&sblock, SIGQUIT));
  401.   (void) (sigaddset (&sblock, SIGTERM));
  402.   (void) (sigaddset (&sblock, SIGPIPE));
  403.  
  404.   (void) sigprocmask (SIG_BLOCK, &sblock, &sold);
  405.   return sold;
  406. }
  407.  
  408. #define usunblocksigs(s) \
  409.   ((void) sigprocmask (SIG_SETMASK, &(s), (sigset_t *) NULL))
  410.  
  411. #else /* ! HAVE_SIGPROCMASK */
  412. #if HAVE_SIGBLOCK
  413.  
  414. /* Use the BSD sigblock and sigsetmask calls.  */
  415.  
  416. #define HELD_SIG_MASK int
  417.  
  418. #ifndef sigmask
  419. #define sigmask(i) (1 << ((i) - 1))
  420. #endif
  421.  
  422. #define isblocksigs() \
  423.   sigblock (sigmask (SIGINT) | sigmask (SIGQUIT) \
  424.         | sigmask (SIGTERM) | sigmask (SIGPIPE))
  425.  
  426. #define usunblocksigs(i) ((void) sigsetmask (i))
  427.  
  428. #else /* ! HAVE_SIGBLOCK */
  429.  
  430. #if HAVE_SIGHOLD
  431.  
  432. /* Use the SVR3 sighold and sigrelse calls.  */
  433.  
  434. #define HELD_SIG_MASK int
  435.  
  436. static int isblocksigs P((void));
  437.  
  438. static int
  439. isblocksigs ()
  440. {
  441.   sighold (SIGINT);
  442.   sighold (SIGQUIT);
  443.   sighold (SIGTERM);
  444.   sighold (SIGPIPE);
  445.   return 0;
  446. }
  447.  
  448. static void usunblocksigs P((int));
  449.  
  450. /*ARGSUSED*/
  451. static void
  452. usunblocksigs (i)
  453.      int i;
  454. {
  455.   sigrelse (SIGINT);
  456.   sigrelse (SIGQUIT);
  457.   sigrelse (SIGTERM);
  458.   sigrelse (SIGPIPE);
  459. }
  460.  
  461. #else /* ! HAVE_SIGHOLD */
  462.  
  463. /* We have no way to block signals.  This system will suffer from a
  464.    race condition in fsysdep_modem_close.  */
  465.  
  466. #define HELD_SIG_MASK int
  467.  
  468. #define isblocksigs() 0
  469.  
  470. #define usunblocksigs(i)
  471.  
  472. #endif /* ! HAVE_SIGHOLD */
  473. #endif /* ! HAVE_SIGBLOCK */
  474. #endif /* ! HAVE_SIGPROCMASK */
  475.  
  476. /* Initialize a connection for use on a serial port.  */
  477.  
  478. static boolean
  479. fsserial_init (qconn, qcmds, zdevice)
  480.      struct sconnection *qconn;
  481.      const struct sconncmds *qcmds;
  482.      const char *zdevice;
  483. {
  484.   struct ssysdep_conn *q;
  485.  
  486.   q = (struct ssysdep_conn *) xmalloc (sizeof (struct ssysdep_conn));
  487.   if (zdevice == NULL
  488.       && qconn->qport != NULL
  489.       && qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
  490.     zdevice = qconn->qport->uuconf_zname;
  491.   if (zdevice == NULL)
  492.     q->zdevice = NULL;
  493.   else if (*zdevice == '/')
  494.     q->zdevice = zbufcpy (zdevice);
  495.   else
  496.     {
  497.       size_t clen;
  498.  
  499.       clen = strlen (zdevice);
  500.       q->zdevice = zbufalc (sizeof "/dev/" + clen);
  501.       memcpy (q->zdevice, "/dev/", sizeof "/dev/" - 1);
  502.       memcpy (q->zdevice + sizeof "/dev/" - 1, zdevice, clen);
  503.       q->zdevice[sizeof "/dev/" + clen - 1] = '\0';
  504.     }
  505.   q->o = -1;
  506.   q->ord = -1;
  507.   q->owr = -1;
  508.   q->ftli = FALSE;
  509.   qconn->psysdep = (pointer) q;
  510.   qconn->qcmds = qcmds;
  511.   return TRUE;
  512. }
  513.  
  514. /* Initialize a connection for use on standard input.  */
  515.  
  516. boolean
  517. fsysdep_stdin_init (qconn)
  518.      struct sconnection *qconn;
  519. {
  520.   /* chmod /dev/tty to prevent other users from writing messages to
  521.      it.  This is essentially `mesg n'.  */
  522.   (void) chmod ("/dev/tty", S_IRUSR | S_IWUSR);
  523.   return fsserial_init (qconn, &sstdincmds, (const char *) NULL);
  524. }
  525.  
  526. /* Initialize a connection for use on a modem port.  */
  527.  
  528. boolean
  529. fsysdep_modem_init (qconn)
  530.      struct sconnection *qconn;
  531. {
  532.   return fsserial_init (qconn, &smodemcmds,
  533.             qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdevice);
  534. }
  535.  
  536. /* Initialize a connection for use on a direct port.  */
  537.  
  538. boolean
  539. fsysdep_direct_init (qconn)
  540.      struct sconnection *qconn;
  541. {
  542.   return fsserial_init (qconn, &sdirectcmds,
  543.             qconn->qport->uuconf_u.uuconf_sdirect.uuconf_zdevice);
  544. }
  545.  
  546. /* Free up a serial port.  */
  547.  
  548. static void
  549. usserial_free (qconn)
  550.      struct sconnection *qconn;
  551. {
  552.   struct ssysdep_conn *qsysdep;
  553.  
  554.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  555.   ubuffree (qsysdep->zdevice);
  556.   xfree ((pointer) qsysdep);
  557.   qconn->psysdep = NULL;
  558. }
  559.  
  560. #if HAVE_SEQUENT_LOCKFILES
  561. #define LCK_TEMPLATE "LCK..tty"
  562. #else
  563. #define LCK_TEMPLATE "LCK.."
  564. #endif
  565.  
  566. /* This routine is used for both locking and unlocking.  It is the
  567.    only routine which knows how to translate a device name into the
  568.    name of a lock file.  If it can't figure out a name, it does
  569.    nothing and returns TRUE.  */
  570.  
  571. static boolean
  572. fsserial_lockfile (flok, qconn)
  573.      boolean flok;
  574.      const struct sconnection *qconn;
  575. {
  576.   struct ssysdep_conn *qsysdep;
  577.   const char *z;
  578.   char *zalc;
  579.   boolean fret;
  580.  
  581.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  582.   if (qconn->qport == NULL)
  583.     z = NULL;
  584.   else
  585.     z = qconn->qport->uuconf_zlockname;
  586.   zalc = NULL;
  587.   if (z == NULL)
  588.     {
  589. #if HAVE_QNX_LOCKFILES
  590.       {
  591.     nid_t idevice_nid;
  592.     char abdevice_nid[13]; /* length of long, a period, and a NUL */
  593.     size_t cdevice_nid;
  594.     const char *zbase;
  595.     size_t clen;
  596.  
  597.         /* If the node ID is explicitly specified as part of the
  598.            pathname to the device, use that.  Otherwise, presume the
  599.            device is local to the current node. */
  600.         if (qsysdep->zdevice[0] == '/' && qsysdep->zdevice[1] == '/')
  601.           idevice_nid = (nid_t) strtol (qsysdep->zdevice + 2,
  602.                     (char **) NULL, 10);
  603.         else
  604.           idevice_nid = getnid ();
  605.  
  606.         sprintf (abdevice_nid, "%ld.", (long) idevice_nid);
  607.         cdevice_nid = strlen (abdevice_nid);
  608.  
  609.      zbase = strrchr (qsysdep->zdevice, '/') + 1;
  610.      clen = strlen (zbase);
  611.  
  612.         zalc = zbufalc (sizeof LCK_TEMPLATE + cdevice_nid + clen);
  613.  
  614.     memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
  615.     memcpy (zalc + sizeof LCK_TEMPLATE - 1, abdevice_nid, cdevice_nid);
  616.     memcpy (zalc + sizeof LCK_TEMPLATE - 1 + cdevice_nid,
  617.         zbase, clen + 1);
  618.  
  619.     z = zalc;
  620.       }
  621. #else /* ! HAVE_QNX_LOCKFILES */
  622. #if ! HAVE_SVR4_LOCKFILES
  623.       {
  624.     const char *zbase;
  625.     size_t clen;
  626.  
  627.     zbase = strrchr (qsysdep->zdevice, '/') + 1;
  628.     clen = strlen (zbase);
  629.     zalc = zbufalc (sizeof LCK_TEMPLATE + clen);
  630.     memcpy (zalc, LCK_TEMPLATE, sizeof LCK_TEMPLATE - 1);
  631.     memcpy (zalc + sizeof LCK_TEMPLATE - 1, zbase, clen + 1);
  632. #if HAVE_SCO_LOCKFILES
  633.     {
  634.       char *zl;
  635.  
  636.       for (zl = zalc + sizeof LCK_TEMPLATE - 1; *zl != '\0'; zl++)
  637.         if (isupper (*zl))
  638.           *zl = tolower (*zl);
  639.     }
  640. #endif
  641.     z = zalc;
  642.       }
  643. #else /* HAVE_SVR4_LOCKFILES */
  644.       {
  645.     struct stat s;
  646.  
  647.     if (stat (qsysdep->zdevice, &s) != 0)
  648.       {
  649.         ulog (LOG_ERROR, "stat (%s): %s", qsysdep->zdevice,
  650.           strerror (errno));
  651.         return FALSE;
  652.       }
  653.     zalc = zbufalc (sizeof "LK.1234567890.1234567890.1234567890");
  654.     sprintf (zalc, "LK.%03d.%03d.%03d", major (s.st_dev),
  655.          major (s.st_rdev), minor (s.st_rdev));
  656.     z = zalc;
  657.       }
  658. #endif /* HAVE_SVR4_LOCKFILES */
  659. #endif /* ! HAVE_QNX_LOCKFILES */
  660.     }
  661.  
  662.   if (flok)
  663.     fret = fsdo_lock (z, FALSE, (boolean *) NULL);
  664.   else
  665.     fret = fsdo_unlock (z, FALSE);
  666.  
  667. #if HAVE_COHERENT_LOCKFILES
  668.   if (fret)
  669.     {
  670.       if (flok)
  671.     {
  672.       if (lockttyexist (z + sizeof LCK_TEMPLATE - 1))
  673.         {
  674.           ulog (LOG_NORMAL, "%s: port already locked",
  675.             z + sizeof LCK_TEMPLATE - 1);
  676.           fret = FALSE;
  677.         }
  678.       else
  679.         fret = fscoherent_disable_tty (z + sizeof LCK_TEMPLATE - 1,
  680.                        &qsysdep->zenable);
  681.     }
  682.       else
  683.     {
  684.       fret = TRUE;
  685.       if (qsysdep->zenable != NULL)
  686.         {
  687.           const char *azargs[3];
  688.           int aidescs[3];
  689.           pid_t ipid;
  690.  
  691.           azargs[0] = "/etc/enable";
  692.           azargs[1] = qsysdep->zenable;
  693.           azargs[2] = NULL;
  694.           aidescs[0] = SPAWN_NULL;
  695.           aidescs[1] = SPAWN_NULL;
  696.           aidescs[2] = SPAWN_NULL;
  697.  
  698.           ipid = ixsspawn (azargs, aidescs, TRUE, FALSE,
  699.                    (const char *) NULL, TRUE, TRUE,
  700.                    (const char *) NULL, (const char *) NULL,
  701.                    (const char *) NULL);
  702.           if (ipid < 0)
  703.         {
  704.           ulog (LOG_ERROR, "ixsspawn (/etc/enable %s): %s",
  705.             qsysdep->zenable, strerror (errno));
  706.           fret = FALSE;
  707.         }
  708.           else
  709.         {
  710.           if (ixswait ((unsigned long) ipid, (const char *) NULL)
  711.               == 0)
  712.             fret = TRUE;
  713.           else
  714.             fret = FALSE;
  715.         }
  716.           ubuffree (qsysdep->zenable);
  717.           qsysdep->zenable = NULL;
  718.         }
  719.     }
  720.     }
  721. #endif /* HAVE_COHERENT_LOCKFILES */
  722.  
  723.   ubuffree (zalc);
  724.   return fret;
  725. }
  726.  
  727. /* If we can mark a modem line in use, then when we lock a port we
  728.    must open it and mark it in use.  We can't wait until the actual
  729.    open because we can't fail out if it is locked then.  */
  730.  
  731. static boolean
  732. fsserial_lock (qconn, fin)
  733.      struct sconnection *qconn;
  734.      boolean fin;
  735. {
  736.   if (! fsserial_lockfile (TRUE, qconn))
  737.     return FALSE;
  738.  
  739. #if HAVE_TIOCSINUSE || HAVE_TIOCEXCL || HAVE_DEV_INFO
  740.   /* Open the line and try to mark it in use.  */
  741.   {
  742.     struct ssysdep_conn *qsysdep;
  743.     int iflag;
  744.  
  745.     qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  746.  
  747.     if (fin)
  748.       iflag = 0;
  749.     else
  750.       iflag = iSunblock;
  751.  
  752.     qsysdep->o = open (qsysdep->zdevice, O_RDWR | iflag);
  753.     if (qsysdep->o < 0)
  754.       {
  755. #if O_NONBLOCK != 0
  756.     if (! fin && iSunblock != O_NONBLOCK && errno == EINVAL)
  757.       {
  758.         iSunblock = O_NONBLOCK;
  759.         qsysdep->o = open (qsysdep->zdevice,
  760.                    O_RDWR | O_NONBLOCK);
  761.       }
  762. #endif
  763.     if (qsysdep->o < 0)
  764.       {
  765.         if (errno != EBUSY)
  766.           ulog (LOG_ERROR, "open (%s): %s", qsysdep->zdevice,
  767.             strerror (errno));
  768.         (void) fsserial_lockfile (FALSE, qconn);
  769.         return FALSE;
  770.       }
  771.       }
  772.  
  773. #if HAVE_TIOCSINUSE
  774.     /* If we can't mark it in use, return FALSE to indicate that the
  775.        lock failed.  */
  776.     if (ioctl (qsysdep->o, TIOCSINUSE, 0) < 0)
  777.       {
  778.     if (errno != EALREADY)
  779.       ulog (LOG_ERROR, "ioctl (TIOCSINUSE): %s", strerror (errno));
  780. #ifdef TIOCNOTTY
  781.     (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
  782. #endif
  783.     (void) close (qsysdep->o);
  784.     qsysdep->o = -1;
  785.     (void) fsserial_lockfile (FALSE, qconn);
  786.     return FALSE;
  787.       }
  788. #endif
  789.  
  790. #if HAVE_DEV_INFO
  791.     /* QNX programs "lock" a serial port by simply opening it and
  792.        checking if some other program also has the port open.  If the
  793.        count of openers is greater than one, the program presumes the
  794.        port is "locked" and backs off.  This isn't really "locking" of
  795.        course, but it pretty much seems to work.  This can result in
  796.        dropping incoming connections if an outgoing connection is
  797.        started at exactly the same time.  It would probably be better
  798.        to stop using the lock files at all for this case, but that
  799.        would involve more complex changes to the code, and I'm afraid
  800.        I would break something.  -- Joe Wells <jbw@cs.bu.edu>  */
  801.     {
  802.       struct _dev_info_entry sdevinfo;
  803.  
  804.       if (dev_info (qsysdep->o, &sdevinfo) == -1)
  805.         {
  806.           ulog (LOG_ERROR, "dev_info: %s", strerror (errno));
  807.           sdevinfo.open_count = 2; /* force presumption of "locked" */
  808.         }
  809.       if (sdevinfo.open_count != 1)
  810.         {
  811. #ifdef TIOCNOTTY
  812.           (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
  813. #endif /* TIOCNOTTY */
  814.           (void) close (qsysdep->o);
  815.           qsysdep->o = -1;
  816.           (void) fsserial_lockfile (FALSE, qconn);
  817.           return FALSE;
  818.         }
  819.     }
  820. #endif /* HAVE_DEV_INFO */
  821.  
  822.     if (fcntl (qsysdep->o, F_SETFD,
  823.            fcntl (qsysdep->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
  824.       {
  825.     ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
  826. #ifdef TIOCNOTTY
  827.     (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
  828. #endif
  829.     (void) close (qsysdep->o);
  830.     qsysdep->o = -1;
  831.     (void) fsserial_lockfile (FALSE, qconn);
  832.     return FALSE;
  833.       }
  834.   }
  835. #endif /* HAVE_TIOCSINUSE || HAVE_TIOCEXCL */
  836.  
  837.   return TRUE;
  838. }
  839.  
  840. /* Unlock a modem or direct port.  */
  841.  
  842. static boolean
  843. fsserial_unlock (qconn)
  844.      struct sconnection *qconn;
  845. {
  846.   boolean fret;
  847.   struct ssysdep_conn *qsysdep;
  848.  
  849.   fret = TRUE;
  850.  
  851.   /* The file may have been opened by fsserial_lock, so close it here
  852.      if necessary.  */
  853.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  854.   if (qsysdep->o >= 0)
  855.     {
  856. #ifdef TIOCNOTTY
  857.       (void) ioctl (qsysdep->o, TIOCNOTTY, (char *) NULL);
  858. #endif
  859.       if (close (qsysdep->o) < 0)
  860.     {
  861.       ulog (LOG_ERROR, "close: %s", strerror (errno));
  862.       fret = FALSE;
  863.     }
  864.       qsysdep->o = -1;
  865.     }
  866.     
  867.   if (! fsserial_lockfile (FALSE, qconn))
  868.     fret = FALSE;
  869.  
  870.   return fret;
  871. }
  872.  
  873. /* A table to map baud rates into index numbers.  */
  874.  
  875. #if HAVE_POSIX_TERMIOS
  876. typedef speed_t baud_code;
  877. #else
  878. typedef int baud_code;
  879. #endif
  880.  
  881. static struct sbaud_table
  882. {
  883.   baud_code icode;
  884.   long ibaud;
  885. } asSbaud_table[] =
  886. {
  887.   { B50, 50 },
  888.   { B75, 75 },
  889.   { B110, 110 },
  890.   { B134, 134 },
  891.   { B150, 150 },
  892.   { B200, 200 },
  893.   { B300, 300 },
  894.   { B600, 600 },
  895.   { B1200, 1200 },
  896.   { B1800, 1800 },
  897.   { B2400, 2400 },
  898.   { B4800, 4800 },
  899.   { B9600, 9600 },
  900. #ifdef B19200
  901.   { B19200, 19200 },
  902. #else /* ! defined (B19200) */
  903. #ifdef EXTA
  904.   { EXTA, 19200 },
  905. #endif /* EXTA */
  906. #endif /* ! defined (B19200) */
  907. #ifdef B38400
  908.   { B38400, 38400 },
  909. #else /* ! defined (B38400) */
  910. #ifdef EXTB
  911.   { EXTB, 38400 },
  912. #endif /* EXTB */
  913. #endif /* ! defined (B38400) */
  914. #ifdef B57600
  915.   { B57600, 57600 },
  916. #endif
  917. #ifdef B76800
  918.   { B76800, 76800 },
  919. #endif
  920. #ifdef B115200
  921.   { B115200, 115200 },
  922. #endif
  923.   { B0, 0 }
  924. };
  925.  
  926. #define CBAUD_TABLE (sizeof asSbaud_table / sizeof asSbaud_table[0])
  927.  
  928. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  929. /* Hold the MIN value for the terminal to avoid setting it
  930.    unnecessarily.  */
  931. static int cSmin;
  932. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  933.  
  934. /* Open a serial line.  This sets the terminal settings.  We begin in
  935.    seven bit mode and let the protocol change if necessary.  If fwait
  936.    is FALSE we open the terminal in non-blocking mode.  If flocal is
  937.    TRUE we set CLOCAL on the terminal when using termio[s]; this is
  938.    supposedly required on some versions of BSD/386.  */
  939.  
  940. static boolean
  941. fsserial_open (qconn, ibaud, fwait, tlocal)
  942.      struct sconnection *qconn;
  943.      long ibaud;
  944.      boolean fwait;
  945.      enum tclocal_setting tlocal;
  946. {
  947.   struct ssysdep_conn *q;
  948.   baud_code ib;
  949.  
  950.   q = (struct ssysdep_conn *) qconn->psysdep;
  951.  
  952.   if (q->zdevice != NULL)
  953.     {
  954. #if LOG_DEVICE_PREFIX
  955.       ulog_device (q->zdevice);
  956. #else
  957.       const char *z;
  958.  
  959.       if (strncmp (q->zdevice, "/dev/", sizeof "/dev/" - 1) == 0)
  960.     z = q->zdevice + sizeof "/dev/" - 1;
  961.       else
  962.     z = q->zdevice;
  963.       ulog_device (z);
  964. #endif
  965.     }
  966.   else
  967.     {
  968.       const char *zport;
  969.       boolean fdummy;
  970.  
  971. #if DEBUG > 0
  972.       if (qconn->qport != NULL &&
  973.       qconn->qport->uuconf_ttype != UUCONF_PORTTYPE_STDIN)
  974.     ulog (LOG_FATAL, "fsserial_open: Can't happen");
  975. #endif
  976.       zport = zsysdep_port_name (&fdummy);
  977.       if (zport != NULL)
  978.     ulog_device (zport);
  979.     }
  980.  
  981.   ib = B0;
  982.   if (ibaud != 0)
  983.     {
  984.       int i;
  985.  
  986.       for (i = 0; i < CBAUD_TABLE; i++)
  987.     if (asSbaud_table[i].ibaud == ibaud)
  988.       break;
  989.       if (i >= CBAUD_TABLE)
  990.     {
  991.       ulog (LOG_ERROR, "Unsupported baud rate %ld", ibaud);
  992.       return FALSE;
  993.     }
  994.       ib = asSbaud_table[i].icode;
  995.     }
  996.  
  997.   /* The port may have already been opened by the locking routine.  */
  998.   if (q->o < 0)
  999.     {
  1000.       int iflag;
  1001.  
  1002.       if (fwait)
  1003.     iflag = 0;
  1004.       else
  1005.     iflag = iSunblock;
  1006.  
  1007.       q->o = open (q->zdevice, O_RDWR | iflag);
  1008.       if (q->o < 0)
  1009.     {
  1010. #if O_NONBLOCK != 0
  1011.       if (! fwait && iSunblock != O_NONBLOCK && errno == EINVAL)
  1012.         {
  1013.           iSunblock = O_NONBLOCK;
  1014.           q->o = open (q->zdevice, O_RDWR | O_NONBLOCK);
  1015.         }
  1016. #endif
  1017.       if (q->o < 0)
  1018.         {
  1019.           ulog (LOG_ERROR, "open (%s): %s", q->zdevice,
  1020.             strerror (errno));
  1021.           return FALSE;
  1022.         }
  1023.     }
  1024.  
  1025.       if (fcntl (q->o, F_SETFD, fcntl (q->o, F_GETFD, 0) | FD_CLOEXEC) < 0)
  1026.     {
  1027.       ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
  1028.       return FALSE;
  1029.     }
  1030.     }
  1031.  
  1032.   /* Get the port flags, and make sure the ports are blocking.  */
  1033.  
  1034.   q->iflags = fcntl (q->o, F_GETFL, 0);
  1035.   if (q->iflags < 0)
  1036.     {
  1037.       ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
  1038.       return FALSE;
  1039.     }
  1040.   q->iwr_flags = -1;
  1041.  
  1042.   if (! fgetterminfo (q->o, &q->sorig))
  1043.     {
  1044.       q->fterminal = FALSE;
  1045.       return TRUE;
  1046.     }
  1047.  
  1048.   q->fterminal = TRUE;
  1049.  
  1050.   q->snew = q->sorig;
  1051.  
  1052. #if HAVE_BSD_TTY
  1053.  
  1054.   q->snew.stty.sg_flags = RAW | ANYP;
  1055.   if (ibaud == 0)
  1056.     ib = q->snew.stty.sg_ospeed;
  1057.   else
  1058.     {
  1059.       q->snew.stty.sg_ispeed = ib;
  1060.       q->snew.stty.sg_ospeed = ib;
  1061.     }
  1062.  
  1063.   /* We don't want to receive any interrupt characters.  */
  1064.   q->snew.stchars.t_intrc = -1;
  1065.   q->snew.stchars.t_quitc = -1;
  1066.   q->snew.stchars.t_eofc = -1;
  1067.   q->snew.stchars.t_brkc = -1;
  1068.   q->snew.sltchars.t_suspc = -1;
  1069.   q->snew.sltchars.t_rprntc = -1;
  1070.   q->snew.sltchars.t_dsuspc = -1;
  1071.   q->snew.sltchars.t_flushc = -1;
  1072.   q->snew.sltchars.t_werasc = -1;
  1073.   q->snew.sltchars.t_lnextc = -1;
  1074.  
  1075. #ifdef NTTYDISC
  1076.   /* We want to use the ``new'' terminal driver so that we can use the
  1077.      local mode bits to control XON/XOFF.  */
  1078.   {
  1079.     int iparam;
  1080.  
  1081.     if (ioctl (q->o, TIOCGETD, &iparam) >= 0
  1082.     && iparam != NTTYDISC)
  1083.       {
  1084.     iparam = NTTYDISC;
  1085.     (void) ioctl (q->o, TIOCSETD, &iparam);
  1086.       }
  1087.   }
  1088. #endif
  1089.  
  1090. #ifdef TIOCHPCL
  1091.   /* When the file is closed, hang up the line.  This is a safety
  1092.      measure in case the program crashes.  */
  1093.   (void) ioctl (q->o, TIOCHPCL, 0);
  1094. #endif
  1095.  
  1096. #ifdef TIOCFLUSH
  1097.   {
  1098.     int iparam;
  1099.  
  1100.     /* Flush pending input.  */
  1101. #ifdef FREAD
  1102.     iparam = FREAD;
  1103. #else
  1104.     iparam = 0;
  1105. #endif
  1106.     (void) ioctl (q->o, TIOCFLUSH, &iparam);
  1107.   }
  1108. #endif /* TIOCFLUSH */
  1109.  
  1110. #endif /* HAVE_BSD_TTY */
  1111.  
  1112. #if HAVE_SYSV_TERMIO
  1113.  
  1114.   if (ibaud == 0)
  1115.     ib = q->snew.c_cflag & CBAUD;
  1116.  
  1117.   q->snew.c_iflag &=~ ICLEAR_IFLAG;
  1118.   q->snew.c_oflag &=~ ICLEAR_OFLAG;
  1119.   q->snew.c_cflag &=~ ICLEAR_CFLAG;
  1120.   q->snew.c_cflag |= ib | ISET_CFLAG;
  1121.   q->snew.c_lflag &=~ ICLEAR_LFLAG;
  1122.   cSmin = 1;
  1123.   q->snew.c_cc[VMIN] = cSmin;
  1124.   q->snew.c_cc[VTIME] = 1;
  1125.  
  1126. #ifdef TCFLSH
  1127.   /* Flush pending input.  */
  1128.   (void) ioctl (q->o, TCFLSH, 0);
  1129. #endif
  1130.  
  1131. #endif /* HAVE_SYSV_TERMIO */
  1132.  
  1133. #if HAVE_POSIX_TERMIOS
  1134.  
  1135.   if (ibaud == 0)
  1136.     ib = cfgetospeed (&q->snew);
  1137.  
  1138.   q->snew.c_iflag &=~ ICLEAR_IFLAG;
  1139.   q->snew.c_oflag &=~ ICLEAR_OFLAG;
  1140.   q->snew.c_cflag &=~ ICLEAR_CFLAG;
  1141.   q->snew.c_cflag |= ISET_CFLAG;
  1142.   q->snew.c_lflag &=~ ICLEAR_LFLAG;
  1143.   cSmin = 1;
  1144.   q->snew.c_cc[VMIN] = cSmin;
  1145.   q->snew.c_cc[VTIME] = 1;
  1146.  
  1147.   (void) cfsetospeed (&q->snew, ib);
  1148.   (void) cfsetispeed (&q->snew, ib);
  1149.  
  1150.   /* Flush pending input.  */
  1151.   (void) tcflush (q->o, TCIFLUSH);
  1152.  
  1153. #endif /* HAVE_POSIX_TERMIOS */
  1154.  
  1155. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1156.   switch (tlocal)
  1157.     {
  1158.     case SET_CLOCAL:
  1159.       q->snew.c_cflag |= CLOCAL;
  1160.       break;
  1161.     case CLEAR_CLOCAL:
  1162.       q->snew.c_cflag &=~ CLOCAL;
  1163.       break;
  1164.     case IGNORE_CLOCAL:
  1165.       break;
  1166.     }
  1167. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  1168.  
  1169.   if (! fsetterminfo (q->o, &q->snew))
  1170.     {
  1171.       ulog (LOG_ERROR, "Can't set terminal settings: %s", strerror (errno));
  1172.       return FALSE;
  1173.     }
  1174.  
  1175. #ifdef TIOCSCTTY
  1176.   /* On BSD 4.4, make it our controlling terminal.  */
  1177.   (void) ioctl (q->o, TIOCSCTTY, 0);
  1178. #endif
  1179.  
  1180.   if (ibaud != 0)
  1181.     q->ibaud = ibaud;
  1182.   else
  1183.     {
  1184.       int i;
  1185.  
  1186.       q->ibaud = (long) 1200;
  1187.       for (i = 0; i < CBAUD_TABLE; i++)
  1188.     {
  1189.       if (asSbaud_table[i].icode == ib)
  1190.         {
  1191.           q->ibaud = asSbaud_table[i].ibaud;
  1192.           break;
  1193.         }
  1194.     }
  1195.  
  1196.       DEBUG_MESSAGE1 (DEBUG_PORT,
  1197.               "fsserial_open: Baud rate is %ld", q->ibaud);
  1198.     }
  1199.  
  1200.   return TRUE;
  1201. }
  1202.  
  1203. /* Open a standard input port.  The code alternates q->o between
  1204.    q->ord and q->owr as appropriate.  It is always q->ord before any
  1205.    call to fsblock.  */
  1206.  
  1207. static boolean
  1208. fsstdin_open (qconn, ibaud, fwait)
  1209.      struct sconnection *qconn;
  1210.      long ibaud;
  1211.      boolean fwait;
  1212. {
  1213.   struct ssysdep_conn *q;
  1214.  
  1215.   q = (struct ssysdep_conn *) qconn->psysdep;
  1216.   q->ord = 0;
  1217.   q->owr = 1;
  1218.  
  1219.   q->o = q->ord;
  1220.   if (! fsserial_open (qconn, ibaud, fwait, IGNORE_CLOCAL))
  1221.     return FALSE;
  1222.   q->iwr_flags = fcntl (q->owr, F_GETFL, 0);
  1223.   if (q->iwr_flags < 0)
  1224.     {
  1225.       ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
  1226.       return FALSE;
  1227.     }
  1228.   return TRUE;
  1229. }
  1230.  
  1231. /* Open a modem port.  */
  1232.  
  1233. static boolean
  1234. fsmodem_open (qconn, ibaud, fwait)
  1235.      struct sconnection *qconn;
  1236.      long ibaud;
  1237.      boolean fwait;
  1238. {
  1239.   struct uuconf_modem_port *qm;
  1240.  
  1241.   qm = &qconn->qport->uuconf_u.uuconf_smodem;
  1242.   if (ibaud == (long) 0)
  1243.     ibaud = qm->uuconf_ibaud;
  1244.  
  1245.   if (! fsserial_open (qconn, ibaud, fwait,
  1246.                fwait ? CLEAR_CLOCAL : SET_CLOCAL))
  1247.     return FALSE;
  1248.  
  1249.   /* If we are waiting for carrier, then turn on hardware flow
  1250.      control.  We don't turn on hardware flow control when dialing
  1251.      out, because some modems don't assert the necessary signals until
  1252.      they see carrier.  Instead, we turn on hardware flow control in
  1253.      fsmodem_carrier.  */
  1254.   if (fwait
  1255.       && ! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
  1256.     return FALSE;
  1257.  
  1258.   return TRUE;
  1259. }
  1260.  
  1261. /* Open a direct port.  */
  1262.  
  1263. static boolean
  1264. fsdirect_open (qconn, ibaud, fwait)
  1265.      struct sconnection *qconn;
  1266.      long ibaud;
  1267.      boolean fwait;
  1268. {
  1269.   struct uuconf_direct_port *qd;
  1270.  
  1271.   qd = &qconn->qport->uuconf_u.uuconf_sdirect;
  1272.   if (ibaud == (long) 0)
  1273.     ibaud = qd->uuconf_ibaud;
  1274.   if (! fsserial_open (qconn, ibaud, fwait,
  1275.                qd->uuconf_fcarrier ? CLEAR_CLOCAL : SET_CLOCAL))
  1276.     return FALSE;
  1277.  
  1278.   /* Always turn on hardware flow control for a direct port when it is
  1279.      opened.  There is no other sensible time to turn it on.  */
  1280.   return fsserial_hardflow (qconn, qd->uuconf_fhardflow);
  1281. }
  1282.  
  1283. /* Change the blocking status of the port.  We keep track of the
  1284.    current blocking status to avoid calling fcntl unnecessarily; fcntl
  1285.    turns out to be surprisingly expensive, at least on Ultrix.  */
  1286.  
  1287. static boolean
  1288. fsblock (qs, fblock)
  1289.      struct ssysdep_conn *qs;
  1290.      boolean fblock;
  1291. {
  1292.   int iwant;
  1293.   int isys;
  1294.  
  1295.   if (fblock)
  1296.     iwant = qs->iflags &~ (O_NDELAY | O_NONBLOCK);
  1297.   else
  1298.     iwant = qs->iflags | iSunblock;
  1299.  
  1300.   if (iwant == qs->iflags)
  1301.     return TRUE;
  1302.  
  1303.   isys = fcntl (qs->o, F_SETFL, iwant);
  1304.   if (isys < 0)
  1305.     {
  1306. #if O_NONBLOCK != 0
  1307.       if (! fblock && iSunblock != O_NONBLOCK && errno == EINVAL)
  1308.     {
  1309.       iSunblock = O_NONBLOCK;
  1310.       iwant = qs->iflags | O_NONBLOCK;
  1311.       isys = fcntl (qs->o, F_SETFL, iwant);
  1312.     }
  1313. #endif
  1314.       if (isys < 0)
  1315.     {
  1316.       ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
  1317.       return FALSE;
  1318.     }
  1319.     }
  1320.  
  1321.   qs->iflags = iwant;
  1322.  
  1323.   if (qs->iwr_flags >= 0 && qs->ord != qs->owr)
  1324.     {
  1325.       if (fblock)
  1326.     iwant = qs->iwr_flags &~ (O_NDELAY | O_NONBLOCK);
  1327.       else
  1328.     iwant = qs->iwr_flags | iSunblock;
  1329.  
  1330.       if (fcntl (qs->owr, F_SETFL, iwant) < 0)
  1331.     {
  1332.       /* We don't bother to fix up iSunblock here, since we
  1333.          succeeded above.  */
  1334.       ulog (LOG_ERROR, "fcntl: %s", strerror (errno));
  1335.       return FALSE;
  1336.     }
  1337.  
  1338.       qs->iwr_flags = iwant;
  1339.     }
  1340.  
  1341.   return TRUE;
  1342. }
  1343.  
  1344. /* Close a serial port.  */
  1345.  
  1346. static boolean
  1347. fsserial_close (q)
  1348.      struct ssysdep_conn *q;
  1349. {
  1350.   if (q->o >= 0)
  1351.     {
  1352.       /* Use a 30 second timeout to avoid hanging while draining
  1353.      output.  */
  1354.       if (q->fterminal)
  1355.     {
  1356.       fSalarm = FALSE;
  1357.  
  1358.       if (fsysdep_catch ())
  1359.         {
  1360.           usysdep_start_catch ();
  1361.           usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
  1362.           (void) alarm (30);
  1363.  
  1364.           (void) fsetterminfodrain (q->o, &q->sorig);
  1365.         }
  1366.  
  1367.       usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  1368.       (void) alarm (0);
  1369.       usysdep_end_catch ();
  1370.  
  1371.       /* If we timed out, use the non draining call.  Hopefully
  1372.          this can't hang.  */
  1373.       if (fSalarm)
  1374.         (void) fsetterminfo (q->o, &q->sorig);
  1375.     }
  1376.  
  1377. #ifdef TIOCNOTTY
  1378.       /* We don't want this as our controlling terminal any more, so
  1379.      get rid of it.  This is necessary because we don't want to
  1380.      open /dev/tty, since that can confuse the serial port locking
  1381.      on some computers.  */
  1382.       (void) ioctl (q->o, TIOCNOTTY, (char *) NULL);
  1383. #endif
  1384.  
  1385.       (void) close (q->o);
  1386.       q->o = -1;
  1387.  
  1388.       /* Sleep to give the terminal a chance to settle, in case we are
  1389.      about to call out again.  */
  1390.       sleep (2);
  1391.     }
  1392.  
  1393.   return TRUE;
  1394. }
  1395.  
  1396. /* Close a stdin port.  */
  1397.  
  1398. /*ARGSUSED*/
  1399. static boolean
  1400. fsstdin_close (qconn, puuconf, qdialer, fsuccess)
  1401.      struct sconnection *qconn;
  1402.      pointer puuconf;
  1403.      struct uuconf_dialer *qdialer;
  1404.      boolean fsuccess;
  1405. {
  1406.   struct ssysdep_conn *qsysdep;
  1407.  
  1408.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  1409.   (void) close (qsysdep->owr);
  1410.   (void) close (2);
  1411.   qsysdep->o = qsysdep->ord;
  1412.   return fsserial_close (qsysdep);
  1413. }
  1414.  
  1415. /* Close a modem port.  */
  1416.  
  1417. static boolean
  1418. fsmodem_close (qconn, puuconf, qdialer, fsuccess)
  1419.      struct sconnection *qconn;
  1420.      pointer puuconf;
  1421.      struct uuconf_dialer *qdialer;
  1422.      boolean fsuccess;
  1423. {
  1424.   struct ssysdep_conn *qsysdep;
  1425.   boolean fret;
  1426.   struct uuconf_dialer sdialer;
  1427.   const struct uuconf_chat *qchat;
  1428.  
  1429.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  1430.  
  1431.   fret = TRUE;
  1432.  
  1433.   /* Figure out the dialer so that we can run the complete or abort
  1434.      chat scripts.  */
  1435.   if (qdialer == NULL)
  1436.     {
  1437.       if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer != NULL)
  1438.     {
  1439.       const char *zdialer;
  1440.       int iuuconf;
  1441.  
  1442.       zdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_pzdialer[0];
  1443.       iuuconf = uuconf_dialer_info (puuconf, zdialer, &sdialer);
  1444.       if (iuuconf == UUCONF_SUCCESS)
  1445.         qdialer = &sdialer;
  1446.       else
  1447.         {
  1448.           ulog_uuconf (LOG_ERROR, puuconf, iuuconf);
  1449.           fret = FALSE;
  1450.         }
  1451.     }
  1452.       else
  1453.     qdialer = qconn->qport->uuconf_u.uuconf_smodem.uuconf_qdialer;
  1454.     }
  1455.  
  1456.   /* Get the complete or abort chat script to use.  */
  1457.   qchat = NULL;
  1458.   if (qdialer != NULL)
  1459.     {
  1460.       if (fsuccess)
  1461.     qchat = &qdialer->uuconf_scomplete;
  1462.       else
  1463.     qchat = &qdialer->uuconf_sabort;
  1464.     }
  1465.  
  1466.   if (qchat != NULL
  1467.       && (qchat->uuconf_pzprogram != NULL
  1468.       || qchat->uuconf_pzchat != NULL))
  1469.     {
  1470.       boolean fsighup_ignored;
  1471.       HELD_SIG_MASK smask;
  1472.       int i;
  1473.       sig_atomic_t afhold[INDEXSIG_COUNT];
  1474.  
  1475.       /* We're no longer interested in carrier.  */
  1476.       (void) fsmodem_carrier (qconn, FALSE);
  1477.  
  1478.       /* The port I/O routines check whether any signal has been
  1479.      received, and abort if one has.  While we are closing down
  1480.      the modem, we don't care if we received a signal in the past,
  1481.      but we do care if we receive a new signal (otherwise it would
  1482.      be difficult to kill a uucico which was closing down a
  1483.      modem).  We never care if we get SIGHUP at this point.  So we
  1484.      turn off SIGHUP, remember what signals we've already seen,
  1485.      and clear our notion of what signals we've seen.  We have to
  1486.      block the signals while we remember and clear the array,
  1487.      since we might otherwise miss a signal which occurred between
  1488.      the copy and the clear (old systems can't block signals; they
  1489.      will just have to suffer the race).  */
  1490.       usset_signal (SIGHUP, SIG_IGN, FALSE, &fsighup_ignored);
  1491.       smask = isblocksigs ();
  1492.       for (i = 0; i < INDEXSIG_COUNT; i++)
  1493.     {
  1494.       afhold[i] = afSignal[i];
  1495.       afSignal[i] = FALSE;
  1496.     }
  1497.       usunblocksigs (smask);
  1498.  
  1499.       if (! fchat (qconn, puuconf, qchat, (const struct uuconf_system *) NULL,
  1500.            (const struct uuconf_dialer *) NULL, (const char *) NULL,
  1501.            FALSE, qconn->qport->uuconf_zname,
  1502.            qsysdep->ibaud))
  1503.     fret = FALSE;
  1504.  
  1505.       /* Restore the old signal array and the SIGHUP handler.  It is
  1506.      not necessary to block signals here, since all we are doing
  1507.      is exactly what the signal handler itself would do if the
  1508.      signal occurred.  */
  1509.       for (i = 0; i < INDEXSIG_COUNT; i++)
  1510.     if (afhold[i])
  1511.       afSignal[i] = TRUE;
  1512.       if (! fsighup_ignored)
  1513.     usset_signal (SIGHUP, ussignal, TRUE, (boolean *) NULL);
  1514.     }
  1515.  
  1516.   if (qdialer != NULL
  1517.       && qdialer == &sdialer)
  1518.     (void) uuconf_dialer_free (puuconf, &sdialer);
  1519.  
  1520. #if ! HAVE_RESET_BUG
  1521.   /* Reset the terminal to make sure we drop DTR.  It should be
  1522.      dropped when we close the descriptor, but that doesn't seem to
  1523.      happen on some systems.  Use a 30 second timeout to avoid hanging
  1524.      while draining output.  */
  1525.   if (qsysdep->fterminal)
  1526.     {
  1527. #if HAVE_BSD_TTY
  1528.       qsysdep->snew.stty.sg_ispeed = B0;
  1529.       qsysdep->snew.stty.sg_ospeed = B0;
  1530. #endif
  1531. #if HAVE_SYSV_TERMIO
  1532.       qsysdep->snew.c_cflag = (qsysdep->snew.c_cflag &~ CBAUD) | B0;
  1533. #endif
  1534. #if HAVE_POSIX_TERMIOS
  1535.       (void) cfsetospeed (&qsysdep->snew, B0);
  1536. #endif
  1537.  
  1538.       fSalarm = FALSE;
  1539.  
  1540.       if (fsysdep_catch ())
  1541.     {
  1542.       usysdep_start_catch ();
  1543.       usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
  1544.       (void) alarm (30);
  1545.  
  1546.       (void) fsetterminfodrain (qsysdep->o, &qsysdep->snew);
  1547.     }
  1548.  
  1549.       usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  1550.       (void) alarm (0);
  1551.       usysdep_end_catch ();
  1552.  
  1553.       /* Let the port settle.  */
  1554.       sleep (2);
  1555.     }
  1556. #endif /* ! HAVE_RESET_BUG */
  1557.  
  1558.   if (! fsserial_close (qsysdep))
  1559.     fret = FALSE;
  1560.  
  1561.   return fret;
  1562. }
  1563.  
  1564. /* Close a direct port.  */
  1565.  
  1566. /*ARGSUSED*/
  1567. static boolean
  1568. fsdirect_close (qconn, puuconf, qdialer, fsuccess)
  1569.      struct sconnection *qconn;
  1570.      pointer puuconf;
  1571.      struct uuconf_dialer *qdialer;
  1572.      boolean fsuccess;
  1573. {
  1574.   return fsserial_close ((struct ssysdep_conn *) qconn->psysdep);
  1575. }
  1576.  
  1577. /* Begin dialing out on a modem port.  This opens the dialer device if
  1578.    there is one.  */
  1579.  
  1580. boolean
  1581. fsysdep_modem_begin_dial (qconn, qdial)
  1582.      struct sconnection *qconn;
  1583.      struct uuconf_dialer *qdial;
  1584. {
  1585.   struct ssysdep_conn *qsysdep;
  1586.   const char *z;
  1587.  
  1588.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  1589.  
  1590. #ifdef TIOCMODEM
  1591.   /* If we can tell the modem to obey modem control, do so.  */
  1592.   {
  1593.     int iperm;
  1594.  
  1595.     iperm = 0;
  1596.     (void) ioctl (qsysdep->o, TIOCMODEM, &iperm);
  1597.   }
  1598. #endif /* TIOCMODEM */
  1599.  
  1600.   /* If we supposed to toggle DTR, do so.  */
  1601.  
  1602.   if (qdial->uuconf_fdtr_toggle)
  1603.     {
  1604. #ifdef TIOCCDTR
  1605.       (void) ioctl (qsysdep->o, TIOCCDTR, 0);
  1606.       sleep (2);
  1607.       (void) ioctl (qsysdep->o, TIOCSDTR, 0);
  1608. #else /* ! defined (TIOCCDTR) */
  1609.       if (qsysdep->fterminal)
  1610.     {
  1611.       sterminal sbaud;
  1612.  
  1613.       sbaud = qsysdep->snew;
  1614.  
  1615. #if HAVE_BSD_TTY
  1616.       sbaud.stty.sg_ispeed = B0;
  1617.       sbaud.stty.sg_ospeed = B0;
  1618. #endif
  1619. #if HAVE_SYSV_TERMIO
  1620.       sbaud.c_cflag = (sbaud.c_cflag &~ CBAUD) | B0;
  1621. #endif
  1622. #if HAVE_POSIX_TERMIOS
  1623.       (void) cfsetospeed (&sbaud, B0);
  1624. #endif
  1625.  
  1626.       (void) fsetterminfodrain (qsysdep->o, &sbaud);
  1627.       sleep (2);
  1628.       (void) fsetterminfo (qsysdep->o, &qsysdep->snew);
  1629.     }
  1630. #endif /* ! defined (TIOCCDTR) */
  1631.  
  1632.       if (qdial->uuconf_fdtr_toggle_wait)
  1633.     sleep (2);
  1634.     }
  1635.  
  1636.   if (! fsmodem_carrier (qconn, FALSE))
  1637.     return FALSE;
  1638.  
  1639.   /* Open the dial device if there is one.  */
  1640.   z = qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device;
  1641.   if (z != NULL)
  1642.     {
  1643.       char *zfree;
  1644.       int o;
  1645.  
  1646.       qsysdep->ohold = qsysdep->o;
  1647.  
  1648.       zfree = NULL;
  1649.       if (*z != '/')
  1650.     {
  1651.       zfree = zbufalc (sizeof "/dev/" + strlen (z));
  1652.       sprintf (zfree, "/dev/%s", z);
  1653.       z = zfree;
  1654.     }
  1655.  
  1656.       o = open ((char *) z, O_RDWR | O_NOCTTY);
  1657.       if (o < 0)
  1658.     {
  1659.       ulog (LOG_ERROR, "open (%s): %s", z, strerror (errno));
  1660.       ubuffree (zfree);
  1661.       return FALSE;
  1662.     }
  1663.       ubuffree (zfree);
  1664.  
  1665.       if (fcntl (o, F_SETFD, fcntl (o, F_GETFD, 0) | FD_CLOEXEC) < 0)
  1666.     {
  1667.       ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
  1668.       (void) close (o);
  1669.       return FALSE;
  1670.     }
  1671.  
  1672.       qsysdep->o = o;
  1673.     }
  1674.  
  1675.   return TRUE;
  1676. }
  1677.  
  1678. /* Tell the port to require or not require carrier.  On BSD this uses
  1679.    TIOCCAR and TIOCNCAR, which I assume are generally supported (it
  1680.    can also use the LNOMDM bit supported by IS68K Unix).  On System V
  1681.    it resets or sets CLOCAL.  We only require carrier if the port
  1682.    supports it.  This will only be called with fcarrier TRUE if the
  1683.    dialer supports carrier.  */
  1684.  
  1685. static boolean
  1686. fsmodem_carrier (qconn, fcarrier)
  1687.      struct sconnection *qconn;
  1688.      boolean fcarrier;
  1689. {
  1690.   register struct ssysdep_conn *q;
  1691.   struct uuconf_modem_port *qm;
  1692.  
  1693.   q = (struct ssysdep_conn *) qconn->psysdep;
  1694.  
  1695.   if (! q->fterminal)
  1696.     return TRUE;
  1697.  
  1698.   qm = &qconn->qport->uuconf_u.uuconf_smodem;
  1699.   if (fcarrier)
  1700.     {
  1701.       if (qm->uuconf_fcarrier)
  1702.     {
  1703. #ifdef TIOCCAR
  1704.       /* Tell the modem to pay attention to carrier.  */
  1705.       if (ioctl (q->o, TIOCCAR, 0) < 0)
  1706.         {
  1707.           ulog (LOG_ERROR, "ioctl (TIOCCAR): %s", strerror (errno));
  1708.           return FALSE;
  1709.         }
  1710. #endif /* TIOCCAR */
  1711.  
  1712. #if HAVE_BSD_TTY
  1713. #ifdef LNOMDM
  1714.       /* IS68K Unix uses a local LNOMDM bit.  */
  1715.       {
  1716.         int iparam;
  1717.  
  1718.         iparam = LNOMDM;
  1719.         if (ioctl (q->o, TIOCLBIC, &iparam) < 0)
  1720.           {
  1721.         ulog (LOG_ERROR, "ioctl (TIOCLBIC, LNOMDM): %s",
  1722.               strerror (errno));
  1723.         return FALSE;
  1724.           }
  1725.       }
  1726. #endif /* LNOMDM */
  1727. #endif /* HAVE_BSD_TTY */
  1728.  
  1729. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1730.       /* Put the modem into nonlocal mode.  */
  1731.       q->snew.c_cflag &=~ CLOCAL;
  1732.       if (! fsetterminfo (q->o, &q->snew))
  1733.         {
  1734.           ulog (LOG_ERROR, "Can't clear CLOCAL: %s", strerror (errno));
  1735.           return FALSE;
  1736.         }
  1737. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  1738.     }
  1739.  
  1740.       /* Turn on hardware flow control after turning on carrier.  We
  1741.      don't do it until now because some modems don't assert the
  1742.      right signals until they see carrier.  */
  1743.       if (! fsserial_hardflow (qconn, qm->uuconf_fhardflow))
  1744.     return FALSE;
  1745.     }
  1746.   else
  1747.     {
  1748.       /* Turn off any hardware flow control before turning off
  1749.      carrier.  */
  1750.       if (! fsserial_hardflow (qconn, FALSE))
  1751.     return FALSE;
  1752.  
  1753. #ifdef TIOCNCAR
  1754.       /* Tell the modem to ignore carrier.  */ 
  1755.       if (ioctl (q->o, TIOCNCAR, 0) < 0)
  1756.     {
  1757.       ulog (LOG_ERROR, "ioctl (TIOCNCAR): %s", strerror (errno));
  1758.       return FALSE;
  1759.     }
  1760. #endif /* TIOCNCAR */
  1761.  
  1762. #if HAVE_BSD_TTY
  1763. #ifdef LNOMDM
  1764.       /* IS68K Unix uses a local LNOMDM bit.  */
  1765.       {
  1766.     int iparam;
  1767.  
  1768.     iparam = LNOMDM;
  1769.     if (ioctl (q->o, TIOCLBIS, &iparam) < 0)
  1770.       {
  1771.         ulog (LOG_ERROR, "ioctl (TIOCLBIS, LNOMDM): %s",
  1772.           strerror (errno));
  1773.         return FALSE;
  1774.       }
  1775.       }
  1776. #endif /* LNOMDM */
  1777. #endif /* HAVE_BSD_TTY */
  1778.  
  1779. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1780.       /* Put the modem into local mode (ignore carrier) to start the chat
  1781.      script.  */
  1782.       q->snew.c_cflag |= CLOCAL;
  1783.       if (! fsetterminfo (q->o, &q->snew))
  1784.     {
  1785.       ulog (LOG_ERROR, "Can't set CLOCAL: %s", strerror (errno));
  1786.       return FALSE;
  1787.     }
  1788.   
  1789. #if HAVE_CLOCAL_BUG
  1790.       /* On SCO and AT&T UNIX PC you have to reopen the port.  */
  1791.       {
  1792.     int onew;
  1793.  
  1794.     onew = open (q->zdevice, O_RDWR);
  1795.     if (onew < 0)
  1796.       {
  1797.         ulog (LOG_ERROR, "open (%s): %s", q->zdevice, strerror (errno));
  1798.         return FALSE;
  1799.       }
  1800.  
  1801.     if (fcntl (onew, F_SETFD,
  1802.            fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
  1803.       {
  1804.         ulog (LOG_ERROR, "fcntl (FD_CLOEXEC): %s", strerror (errno));
  1805.         (void) close (onew);
  1806.         return FALSE;
  1807.       }
  1808.  
  1809.     (void) close (q->o);
  1810.     q->o = onew;
  1811.       }
  1812. #endif /* HAVE_CLOCAL_BUG */
  1813.  
  1814. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  1815.     }
  1816.  
  1817.   return TRUE;
  1818. }
  1819.  
  1820. /* Tell the port to use hardware flow control.  There is no standard
  1821.    mechanism for controlling this.  This implementation supports
  1822.    CRTSCTS on SunOS, RTS/CTSFLOW on 386(ish) unix, CTSCD on the 3b1,
  1823.    CCTS_OFLOW/CRTS_IFLOW on BSDI, TXADDCD/TXDELCD on AIX, and IRTS on
  1824.    NCR Tower.  If you know how to do it on other systems, please
  1825.    implement it and send me the patches.  */
  1826.  
  1827. static boolean
  1828. fsserial_hardflow (qconn, fhardflow)
  1829.      struct sconnection *qconn;
  1830.      boolean fhardflow;
  1831. {
  1832.   register struct ssysdep_conn *q;
  1833.  
  1834.   q = (struct ssysdep_conn *) qconn->psysdep;
  1835.  
  1836.   if (! q->fterminal)
  1837.     return TRUE;
  1838.  
  1839.   /* Don't do anything if we don't know what to do.  */
  1840. #if HAVE_BSD_TTY
  1841. #define HAVE_HARDFLOW 0
  1842. #endif
  1843. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1844. #if ! HAVE_TXADDCD
  1845. #ifndef CRTSFL
  1846. #ifndef CRTSCTS
  1847. #ifndef CTSCD
  1848. #ifndef CCTS_OFLOW
  1849. #ifndef IRTS
  1850. #define HAVE_HARDFLOW 0
  1851. #endif
  1852. #endif
  1853. #endif
  1854. #endif
  1855. #endif
  1856. #endif
  1857. #endif
  1858.  
  1859. #ifndef HAVE_HARDFLOW
  1860. #define HAVE_HARDFLOW 1
  1861. #endif
  1862.  
  1863. #if HAVE_HARDFLOW
  1864.   if (fhardflow)
  1865.     {
  1866. #if HAVE_TXADDCD
  1867.       /* The return value does not reliably indicate whether this
  1868.      actually succeeded.  */
  1869.       (void) ioctl (q->o, TXADDCD, "rts");
  1870. #else /* ! HAVE_TXADDCD */
  1871. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1872. #ifdef CRTSFL
  1873.       q->snew.c_cflag |= CRTSFL;
  1874.       q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
  1875. #endif /* defined (CRTSFL) */
  1876. #ifdef CRTSCTS
  1877.       q->snew.c_cflag |= CRTSCTS;
  1878. #endif /* defined (CRTSCTS) */
  1879. #ifdef CTSCD
  1880.       q->snew.c_cflag |= CTSCD;
  1881. #endif /* defined (CTSCD) */
  1882. #ifdef CCTS_OFLOW
  1883.       q->snew.c_cflag |= CCTS_OFLOW | CRTS_IFLOW;
  1884. #endif
  1885. #ifdef IRTS
  1886.       q->snew.c_iflag |= IRTS;
  1887. #endif
  1888. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  1889.       if (! fsetterminfo (q->o, &q->snew))
  1890.     {
  1891.       ulog (LOG_ERROR, "Can't enable hardware flow control: %s",
  1892.         strerror (errno));
  1893.       return FALSE;
  1894.     }
  1895. #endif /* ! HAVE_TXADDCD */
  1896.     }
  1897.   else
  1898.     {
  1899. #if HAVE_TXADDCD
  1900.       /* The return value does not reliably indicate whether this
  1901.      actually succeeded.  */
  1902.       (void) ioctl (q->o, TXDELCD, "rts");
  1903. #else /* ! HAVE_TXADDCD */
  1904. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  1905. #ifdef CRTSFL
  1906.       q->snew.c_cflag &=~ CRTSFL;
  1907.       q->snew.c_cflag &=~ (RTSFLOW | CTSFLOW);
  1908. #endif /* defined (CRTSFL) */
  1909. #ifdef CRTSCTS
  1910.       q->snew.c_cflag &=~ CRTSCTS;
  1911. #endif /* defined (CRTSCTS) */
  1912. #ifdef CTSCD
  1913.       q->snew.c_cflag &=~ CTSCD;
  1914. #endif /* defined (CTSCD) */
  1915. #ifdef CCTS_OFLOW
  1916.       q->snew.c_cflag &=~ (CCTS_OFLOW | CRTS_IFLOW);
  1917. #endif
  1918. #ifdef IRTS
  1919.       q->snew.c_iflag &=~ IRTS;
  1920. #endif
  1921. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  1922.       if (! fsetterminfo (q->o, &q->snew))
  1923.     {
  1924.       ulog (LOG_ERROR, "Can't disable hardware flow control: %s",
  1925.         strerror (errno));
  1926.       return FALSE;
  1927.     }
  1928. #endif /* ! HAVE_TXADDCD */
  1929.     }
  1930. #endif /* HAVE_HARDFLOW */
  1931.  
  1932.   return TRUE;
  1933. }
  1934.  
  1935. /* Finish dialing out on a modem by closing any dialer device and waiting
  1936.    for carrier.  */
  1937.  
  1938. boolean
  1939. fsysdep_modem_end_dial (qconn, qdial)
  1940.      struct sconnection *qconn;
  1941.      struct uuconf_dialer *qdial;
  1942. {
  1943.   struct ssysdep_conn *q;
  1944.  
  1945.   q = (struct ssysdep_conn *) qconn->psysdep;
  1946.  
  1947.   if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_zdial_device != NULL)
  1948.     {
  1949.       (void) close (q->o);
  1950.       q->o = q->ohold;
  1951.     }
  1952.  
  1953.   if (qconn->qport->uuconf_u.uuconf_smodem.uuconf_fcarrier
  1954.       && qdial->uuconf_fcarrier)
  1955.     {
  1956.       /* Tell the port that we need carrier.  */
  1957.       if (! fsmodem_carrier (qconn, TRUE))
  1958.     return FALSE;
  1959.  
  1960. #ifdef TIOCWONLINE
  1961.  
  1962.       /* We know how to wait for carrier, so do so.  */
  1963.  
  1964.       /* If we already got a signal, just quit now.  */
  1965.       if (FGOT_QUIT_SIGNAL ())
  1966.     return FALSE;
  1967.  
  1968.       /* This bit of code handles signals just like fsysdep_conn_read
  1969.      does.  See that function for a longer explanation.  */
  1970.  
  1971.       /* Use fsysdep_catch to handle a longjmp from the signal
  1972.      handler.  */
  1973.  
  1974.       fSalarm = FALSE;
  1975.  
  1976.       if (fsysdep_catch ())
  1977.     {
  1978.       /* Start catching SIGALRM; normally we ignore it.  */
  1979.       usysdep_start_catch ();
  1980.       usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
  1981.       (void) alarm (qdial->uuconf_ccarrier_wait);
  1982.  
  1983.       /* We really don't care if we get an error, since that will
  1984.          probably just mean that TIOCWONLINE isn't supported in
  1985.          which case there's nothing we can do anyhow.  If we get
  1986.          SIGINT we want to keep waiting for carrier, because
  1987.          SIGINT just means don't start any new sessions.  We don't
  1988.          handle SIGINT correctly if we do a longjmp in the signal
  1989.          handler; too bad.  */
  1990.       while (ioctl (q->o, TIOCWONLINE, 0) < 0
  1991.          && errno == EINTR)
  1992.         {
  1993.           /* Log the signal.  */
  1994.           ulog (LOG_ERROR, (const char *) NULL);
  1995.           if (FGOT_QUIT_SIGNAL () || fSalarm)
  1996.         break;
  1997.         }
  1998.     }
  1999.  
  2000.       /* Turn off the pending SIGALRM and ignore SIGALARM again.  */
  2001.       usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2002.       (void) alarm (0);
  2003.       usysdep_end_catch ();
  2004.  
  2005.       /* If we got a random signal, just return FALSE.  */
  2006.       if (FGOT_QUIT_SIGNAL ())
  2007.     return FALSE;
  2008.  
  2009.       /* If we timed out, give an error.  */
  2010.       if (fSalarm)
  2011.     {
  2012.       ulog (LOG_ERROR, "Timed out waiting for carrier");
  2013.       return FALSE;
  2014.     }
  2015.  
  2016. #else /* ! defined (TIOCWONLINE) */
  2017.  
  2018.       /* Try to open the port again without using O_NDELAY.  In
  2019.      principle, the open should delay until carrier is available.
  2020.      This may not work on some systems, so we just ignore any
  2021.      errors.  */
  2022.       {
  2023.     int onew;
  2024.  
  2025.     onew = open (q->zdevice, O_RDWR);
  2026.     if (onew >= 0)
  2027.       {
  2028.         boolean fbad;
  2029.         int iflags;
  2030.  
  2031.         fbad = FALSE;
  2032.  
  2033.         if (fcntl (onew, F_SETFD,
  2034.                fcntl (onew, F_GETFD, 0) | FD_CLOEXEC) < 0)
  2035.           fbad = TRUE;
  2036.  
  2037.         if (! fbad)
  2038.           {
  2039.         iflags = fcntl (onew, F_GETFL, 0);
  2040.         if (iflags < 0
  2041.             || ! fsetterminfo (onew, &q->snew))
  2042.           fbad = TRUE;
  2043.           }
  2044.  
  2045.         if (fbad)
  2046.           (void) close (onew);
  2047.         else
  2048.           {
  2049.         (void) close (q->o);
  2050.         q->o = onew;
  2051.         q->iflags = iflags;
  2052. #if HAVE_TIOCSINUSE
  2053.         (void) ioctl (onew, TIOCSINUSE, 0);
  2054. #endif
  2055.           }
  2056.       }
  2057.       }
  2058.  
  2059. #endif /* ! defined (TIOCWONLINE) */
  2060.     }
  2061.  
  2062.   return TRUE; 
  2063. }
  2064.  
  2065. /* Read data from a connection, with a timeout.  This routine handles
  2066.    all types of connections, including TLI.
  2067.  
  2068.    This function should return when we have read cmin characters or
  2069.    the timeout has occurred.  We have to work a bit to get Unix to do
  2070.    this efficiently on a terminal.  The simple implementation
  2071.    schedules a SIGALRM signal and then calls read; if there is a
  2072.    single character available, the call to read will return
  2073.    immediately, so there must be a loop which terminates when the
  2074.    SIGALRM is delivered or the correct number of characters has been
  2075.    read.  This can be very inefficient with a fast CPU or a low baud
  2076.    rate (or both!), since each call to read may return only one or two
  2077.    characters.
  2078.  
  2079.    Under POSIX or System V, we can specify a minimum number of
  2080.    characters to read, so there is no serious trouble.
  2081.  
  2082.    Under BSD, we figure out how many characters we have left to read,
  2083.    how long it will take for them to arrive at the current baud rate,
  2084.    and sleep that long.
  2085.  
  2086.    Doing this with a timeout and avoiding all possible race conditions
  2087.    get very hairy, though.  Basically, we're going to schedule a
  2088.    SIGALRM for when the timeout expires.  I don't really want to do a
  2089.    longjmp in the SIGALRM handler, though, because that may lose data.
  2090.    Therefore, I have the signal handler set a variable.  However, this
  2091.    means that there will be a span of time between the time the code
  2092.    checks the variable and the time it calls the read system call; if
  2093.    the SIGALRM occurs during that time, the read might hang forever.
  2094.    To avoid this, the SIGALRM handler not only sets a global variable,
  2095.    it also schedules another SIGALRM for one second in the future
  2096.    (POSIX specifies that a signal handler is permitted to safely call
  2097.    alarm).  To avoid getting a continual sequence of SIGALRM
  2098.    interrupts, we change the signal handler to ignore SIGALRM when
  2099.    we're about to exit the function.  This means that every time we
  2100.    execute fsysdep_conn_read we make at least five system calls.  It's
  2101.    the best I've been able to come up with, though.
  2102.  
  2103.    When fsysdep_conn_read finishes, there will be no SIGALRM scheduled
  2104.    and SIGALRM will be ignored.  */
  2105.  
  2106. boolean
  2107. fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
  2108.      struct sconnection *qconn;
  2109.      char *zbuf;
  2110.      size_t *pclen;
  2111.      size_t cmin;
  2112.      int ctimeout;
  2113.      boolean freport;
  2114. {
  2115.   CATCH_PROTECT size_t cwant;
  2116.   boolean fret;
  2117.   register struct ssysdep_conn * const q
  2118.     = (struct ssysdep_conn *) qconn->psysdep;
  2119.   int cwouldblock;
  2120.  
  2121.   cwant = *pclen;
  2122.   *pclen = 0;
  2123.  
  2124.   /* Guard against a bad timeout.  We return TRUE when a timeout
  2125.      expires.  It is possible to get a negative timeout here because
  2126.      the calling code does not check user supplied timeouts for
  2127.      plausibility.  */
  2128.   if (ctimeout <= 0)
  2129.     return TRUE;
  2130.  
  2131.   /* We want to do a blocking read.  */
  2132.   if (! fsblock (q, TRUE))
  2133.     return FALSE;
  2134.  
  2135.   fSalarm = FALSE;
  2136.  
  2137.   /* We're going to set up an alarm signal to last for the entire
  2138.      read.  If the read system call cannot be interrupted, the signal
  2139.      handler will do a longjmp causing fsysdep_catch (a macro) to
  2140.      return FALSE.  We handle that here.  If read can be interrupted,
  2141.      fsysdep_catch will be defined to TRUE.  */
  2142.   if (fsysdep_catch ())
  2143.     {
  2144.       /* Prepare to catch SIGALRM and schedule the signal.  */
  2145.       usysdep_start_catch ();
  2146.       usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
  2147.       alarm (ctimeout);
  2148.     }
  2149.   else
  2150.     {
  2151.       /* We caught a signal.  We don't actually have to do anything,
  2152.      as all the appropriate checks are made at the start of the
  2153.      following loop.  */
  2154.     }
  2155.  
  2156.   fret = FALSE;
  2157.  
  2158.   cwouldblock = 0;
  2159.   while (TRUE)
  2160.     {
  2161.       int cgot;
  2162.  
  2163. #if HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS
  2164.       /* If we can tell the terminal not to return until we have a
  2165.      certain number of characters, do so.  */
  2166.       if (q->fterminal)
  2167.     {
  2168.       int csetmin;
  2169.  
  2170.       /* I'm not that confident about setting MIN to values larger
  2171.          than 127, although up to 255 would probably work.  */
  2172.       if (cmin < 127)
  2173.         csetmin = cmin;
  2174.       else
  2175.         csetmin = 127;
  2176.  
  2177.       if (csetmin != cSmin)
  2178.         {
  2179.           q->snew.c_cc[VMIN] = csetmin;
  2180.           while (! fsetterminfo (q->o, &q->snew))
  2181.         {
  2182.           if (errno != EINTR
  2183.               || FGOT_QUIT_SIGNAL ())
  2184.             {
  2185.               int ierr;
  2186.  
  2187.               /* We turn off the signal before reporting the
  2188.              error to minimize any problems with
  2189.              interrupted system calls.  */
  2190.               ierr = errno;
  2191.               usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2192.               alarm (0);
  2193.               usysdep_end_catch ();
  2194.               ulog (LOG_ERROR, "Can't set MIN for terminal: %s",
  2195.                 strerror (ierr));
  2196.               return FALSE;
  2197.             }
  2198.  
  2199.           if (fSalarm)
  2200.             {
  2201.               ulog (LOG_ERROR,
  2202.                 "Timed out when setting MIN to %d; retrying",
  2203.                 csetmin);
  2204.               fSalarm = FALSE;
  2205.               alarm (ctimeout);
  2206.             }
  2207.         }
  2208.           cSmin = csetmin;
  2209.         }
  2210.     }
  2211. #endif /* HAVE_SYSV_TERMIO || HAVE_POSIX_TERMIOS */
  2212.  
  2213.       /* If we've received a signal, get out now.  */
  2214.       if (FGOT_QUIT_SIGNAL ())
  2215.     break;
  2216.  
  2217.       /* If we've already gotten a SIGALRM, get out with whatever
  2218.      we've accumulated.  */
  2219.       if (fSalarm)
  2220.     {
  2221.       fret = TRUE;
  2222.       break;
  2223.     }
  2224.  
  2225.       /* Right here is the race condition which we avoid by having the
  2226.      SIGALRM handler schedule another SIGALRM.  */
  2227. #if HAVE_TLI
  2228.       if (q->ftli)
  2229.     {
  2230.       int iflags;
  2231.  
  2232.       cgot = t_rcv (q->o, zbuf, cwant, &iflags);
  2233.       if (cgot < 0 && t_errno != TSYSERR)
  2234.         {
  2235.           usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2236.           alarm (0);
  2237.           usysdep_end_catch ();
  2238.  
  2239.           if (freport)
  2240.         ulog (LOG_ERROR, "t_rcv: %s",
  2241.               (t_errno >= 0 && t_errno < t_nerr
  2242.                ? t_errlist[t_errno]
  2243.                : "unknown TLI error"));
  2244.  
  2245.           return FALSE;
  2246.         }
  2247.     }
  2248.       else
  2249. #endif
  2250.     cgot = read (q->o, zbuf, cwant);
  2251.  
  2252.       /* If the read returned an error, check for signals.  */
  2253.       if (cgot < 0)
  2254.     {
  2255.       if (errno == EINTR)
  2256.         {
  2257.           /* Log the signal.  */
  2258.           ulog (LOG_ERROR, (const char *) NULL);
  2259.         }
  2260.       if (fSalarm)
  2261.         {
  2262.           fret = TRUE;
  2263.           break;
  2264.         }
  2265.       if (FGOT_QUIT_SIGNAL ())
  2266.         break;
  2267.     }
  2268.  
  2269.       /* If read returned an error, get out.  We just ignore EINTR
  2270.      here, since it must be from some signal we don't care about.
  2271.      If the read returned 0 then the line must have been hung up
  2272.      (normally we would have received SIGHUP, but we can't count
  2273.      on that).  We turn off the signals before calling ulog to
  2274.      reduce problems with interrupted system calls.  */
  2275.       if (cgot > 0)
  2276.     cwouldblock = 0;
  2277.       else
  2278.     {
  2279.       if (cgot < 0 && errno == EINTR)
  2280.         cgot = 0;
  2281.       else if (cgot < 0
  2282.            && (errno == EAGAIN || errno == EWOULDBLOCK)
  2283.            && cwouldblock < 2)
  2284.         {
  2285.           /* Incomprehensibly, on some systems the read will
  2286.          return EWOULDBLOCK even though the descriptor has
  2287.          been set to blocking mode.  We permit the read call
  2288.          to do this twice in a row, and then error out.  We
  2289.          don't want to permit an arbitrary number of
  2290.          EWOULDBLOCK errors, since that could hang us up
  2291.          indefinitely.  */
  2292.           ++cwouldblock;
  2293.           cgot = 0;
  2294.         }
  2295.       else
  2296.         {
  2297.           int ierr;
  2298.  
  2299.           ierr = errno;
  2300.  
  2301.           usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2302.           alarm (0);
  2303.           usysdep_end_catch ();
  2304.  
  2305.           if (freport)
  2306.         {
  2307.           if (cgot == 0)
  2308.             ulog (LOG_ERROR, "Line disconnected");
  2309.           else
  2310.             ulog (LOG_ERROR, "read: %s", strerror (ierr));
  2311.         }
  2312.  
  2313.           return FALSE;
  2314.         }
  2315.     }
  2316.  
  2317.       cwant -= cgot;
  2318.       if (cgot >= cmin)
  2319.     cmin = 0;
  2320.       else
  2321.     cmin -= cgot;
  2322.       zbuf += cgot;
  2323.       *pclen += cgot;
  2324.  
  2325.       /* If we have enough data, get out now.  */
  2326.       if (cmin == 0)
  2327.     {
  2328.       fret = TRUE;
  2329.       break;
  2330.     }
  2331.  
  2332. #if HAVE_BSD_TTY
  2333.       /* We still want more data, so sleep long enough for the rest of
  2334.      it to arrive.  We don't this for System V or POSIX because
  2335.      setting MIN is good enough (we can't sleep longer than it
  2336.      takes to get MAX_INPUT characters anyhow).
  2337.  
  2338.      The baud rate is approximately 10 times the number of
  2339.      characters which will arrive in one second, so the number of
  2340.      milliseconds to sleep ==
  2341.      characters * (milliseconds / character) ==
  2342.      characters * (1000 * (seconds / character)) ==
  2343.      characters * (1000 * (1 / (baud / 10))) ==
  2344.      characters * (10000 / baud)
  2345.  
  2346.      We arbitrarily reduce the sleep amount by 10 milliseconds to
  2347.      attempt to account for the amount of time it takes to set up
  2348.      the sleep.  This is how long it takes to get half a character
  2349.      at 19200 baud.  We then don't bother to sleep for less than
  2350.      10 milliseconds.  We don't sleep if the read was interrupted.
  2351.  
  2352.      We use select to sleep.  It would be easy to use poll as
  2353.      well, but it's unlikely that any system with BSD ttys would
  2354.      have poll but not select.  Using select avoids hassles with
  2355.      the pending SIGALRM; if it hits the select will be
  2356.      interrupted, and otherwise the select will not affect it.  */
  2357.  
  2358. #if ! HAVE_SELECT
  2359.  #error This code requires select; feel free to extend it
  2360. #endif
  2361.  
  2362.       if (q->fterminal && cmin > 1 && cgot > 0)
  2363.     {
  2364.       int csleepchars;
  2365.       int isleep;
  2366.  
  2367.       /* We don't try to read all the way up to MAX_INPUT,
  2368.          since that might drop a character.  */
  2369.       if (cmin <= MAX_INPUT - 10)
  2370.         csleepchars = cmin;
  2371.       else
  2372.         csleepchars = MAX_INPUT - 10;
  2373.  
  2374.       isleep = (int) (((long) csleepchars * 10000L) / q->ibaud);
  2375.       isleep -= 10;
  2376.  
  2377.       if (isleep > 10)
  2378.         {
  2379.           struct timeval s;
  2380.  
  2381.           s.tv_sec = isleep / 1000;
  2382.           s.tv_usec = (isleep % 1000) * 1000;
  2383.  
  2384.           /* Some versions of select take a pointer to an int,
  2385.          while some take a pointer to an fd_set.  I just cast
  2386.          the arguments to a generic pointer, and assume that
  2387.          any machine which distinguishes int * from fd_set *
  2388.          (I would be amazed if there are any such machines)
  2389.          have an appropriate prototype somewhere or other.  */
  2390.           (void) select (0, (pointer) NULL, (pointer) NULL,
  2391.                  (pointer) NULL, &s);
  2392.  
  2393.           /* Here either the select finished sleeping or we got a
  2394.          SIGALRM.  If the latter occurred, fSalarm was set to
  2395.          TRUE; it will be checked at the top of the loop.  */
  2396.         }
  2397.     }
  2398. #endif /* HAVE_BSD_TTY */
  2399.     }
  2400.  
  2401.   /* Turn off the pending SIGALRM and return.  */
  2402.  
  2403.   usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2404.   alarm (0);
  2405.   usysdep_end_catch ();
  2406.  
  2407.   return fret;
  2408. }
  2409.  
  2410. /* Read from a port with separate read/write file descriptors.  */
  2411.  
  2412. boolean
  2413. fsdouble_read (qconn, zbuf, pclen, cmin, ctimeout, freport)
  2414.      struct sconnection *qconn;
  2415.      char *zbuf;
  2416.      size_t *pclen;
  2417.      size_t cmin;
  2418.      int ctimeout;
  2419.      boolean freport;
  2420. {
  2421.   struct ssysdep_conn *qsysdep;
  2422.  
  2423.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  2424.   qsysdep->o = qsysdep->ord;
  2425.   return fsysdep_conn_read (qconn, zbuf, pclen, cmin, ctimeout, freport);
  2426. }
  2427.  
  2428. /* Write data to a connection.  This routine handles all types of
  2429.    connections, including TLI.  */
  2430.  
  2431. boolean
  2432. fsysdep_conn_write (qconn, zwrite, cwrite)
  2433.      struct sconnection *qconn;
  2434.      const char *zwrite;
  2435.      size_t cwrite;
  2436. {
  2437.   struct ssysdep_conn *q;
  2438.   int czero;
  2439.  
  2440.   q = (struct ssysdep_conn *) qconn->psysdep;
  2441.  
  2442.   /* We want blocking writes here.  */
  2443.   if (! fsblock (q, TRUE))
  2444.     return FALSE;
  2445.  
  2446.   czero = 0;
  2447.  
  2448.   while (cwrite > 0)
  2449.     {
  2450.       int cdid;
  2451.  
  2452.       /* Loop until we don't get an interrupt.  */
  2453.       while (TRUE)
  2454.     {
  2455.       /* If we've received a signal, don't continue.  */
  2456.       if (FGOT_QUIT_SIGNAL ())
  2457.         return FALSE;
  2458.  
  2459. #if HAVE_TLI
  2460.       if (q->ftli)
  2461.         {
  2462.           cdid = t_snd (q->o, (char *) zwrite, cwrite, 0);
  2463.           if (cdid < 0 && t_errno != TSYSERR)
  2464.         {
  2465.           ulog (LOG_ERROR, "t_snd: %s",
  2466.             (t_errno >= 0 && t_errno < t_nerr
  2467.              ? t_errlist[t_errno]
  2468.              : "unknown TLI error"));
  2469.           return FALSE;
  2470.         }
  2471.         }
  2472.       else
  2473. #endif
  2474.         cdid = write (q->o, zwrite, cwrite);
  2475.  
  2476.       if (cdid >= 0)
  2477.         break;
  2478.       if (errno != EINTR)
  2479.         break;
  2480.  
  2481.       /* We were interrupted by a signal.  Log it.  */
  2482.       ulog (LOG_ERROR, (const char *) NULL);
  2483.     }
  2484.  
  2485.       if (cdid < 0)
  2486.     {
  2487.       if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
  2488.         {
  2489.           ulog (LOG_ERROR, "write: %s", strerror (errno));
  2490.           return FALSE;
  2491.         }
  2492.       cdid = 0;
  2493.     }
  2494.  
  2495.       if (cdid == 0)
  2496.     {
  2497.       /* On some systems write will return 0 if carrier is lost.
  2498.          If we fail to write anything ten times in a row, we
  2499.          assume that this has happened.  This is hacked in like
  2500.          this because there seems to be no reliable way to tell
  2501.          exactly why the write returned 0.  */
  2502.       ++czero;
  2503.       if (czero >= 10)
  2504.         {
  2505.           ulog (LOG_ERROR, "Line disconnected");
  2506.           return FALSE;
  2507.         }
  2508.     }
  2509.       else
  2510.     {
  2511.       czero = 0;
  2512.  
  2513.       cwrite -= cdid;
  2514.       zwrite += cdid;
  2515.     }
  2516.     }
  2517.  
  2518.   return TRUE;
  2519. }
  2520.  
  2521. /* Write to a port with separate read/write file descriptors.  */
  2522.  
  2523. boolean
  2524. fsdouble_write (qconn, zwrite, cwrite)
  2525.      struct sconnection *qconn;
  2526.      const char *zwrite;
  2527.      size_t cwrite;
  2528. {
  2529.   struct ssysdep_conn *qsysdep;
  2530.  
  2531.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  2532.   qsysdep->o = qsysdep->ord;
  2533.   if (! fsblock (qsysdep, TRUE))
  2534.     return FALSE;
  2535.   qsysdep->o = qsysdep->owr;
  2536.   return fsysdep_conn_write (qconn, zwrite, cwrite);
  2537. }
  2538.  
  2539. /* The fsysdep_conn_io routine is supposed to both read and write data
  2540.    until it has either filled its read buffer or written out all the
  2541.    data it was given.  This lets us write out large packets without
  2542.    losing incoming data.  It handles all types of connections,
  2543.    including TLI.  */
  2544.  
  2545. boolean
  2546. fsysdep_conn_io (qconn, zwrite, pcwrite, zread, pcread)
  2547.      struct sconnection *qconn;
  2548.      const char *zwrite;
  2549.      size_t *pcwrite;
  2550.      char *zread;
  2551.      size_t *pcread;
  2552. {
  2553.   struct ssysdep_conn *q;
  2554.   size_t cwrite, cread;
  2555.   int czero;
  2556.  
  2557.   q = (struct ssysdep_conn *) qconn->psysdep;
  2558.  
  2559.   cwrite = *pcwrite;
  2560.   *pcwrite = 0;
  2561.   cread = *pcread;
  2562.   *pcread = 0;
  2563.  
  2564.   czero = 0;
  2565.  
  2566.   while (TRUE)
  2567.     {
  2568.       int cgot, cdid;
  2569.       size_t cdo;
  2570.  
  2571.       /* This used to always use nonblocking writes, but it turns out
  2572.      that some systems don't support them on terminals.
  2573.  
  2574.      The current algorithm is:
  2575.          loop:
  2576.            unblocked read
  2577.            if read buffer full, return
  2578.            if nothing to write, return
  2579.            if HAVE_UNBLOCKED_WRITES
  2580.              write all data
  2581.            else
  2582.              write up to SINGLE_WRITE bytes
  2583.            if all data written, return
  2584.            if no data written
  2585.              if select works
  2586.            select on the write descriptor with a ten second timeout
  2587.          else
  2588.            blocked write of one byte with a ten second alarm
  2589.  
  2590.      This algorithm should work whether the system supports
  2591.      unblocked writes on terminals or not.  If the system supports
  2592.      unblocked writes but HAVE_UNBLOCKED_WRITES is 0, then it will
  2593.      call write more often than it needs to.  If the system does
  2594.      not support unblocked writes but HAVE_UNBLOCKED_WRITES is 1,
  2595.      then the write may hang so long that incoming data is lost.
  2596.      This is actually possible at high baud rates on any system
  2597.      when a blocking write is done; there is no solution, except
  2598.      hardware handshaking.
  2599.  
  2600.      If we were not able to write any data, then we need to block
  2601.      until we can write something.  The code used to simply do a
  2602.      blocking write.  However, that fails when a bidirectional
  2603.      protocol is permitted to push out enough bytes to fill the
  2604.      entire pipe between the two communicating uucico processes.
  2605.      They can both block on writing, because neither is reading.
  2606.  
  2607.      In this case, we use select.  We could select on both the
  2608.      read and write descriptor, but on some systems that would
  2609.      lead to calling read on each byte, which would be very
  2610.      inefficient.  Instead, we select only on the write
  2611.      descriptor.  After the select succeeds or times out, we retry
  2612.      the read.
  2613.  
  2614.      Of course, some systems don't have select, and on some
  2615.      systems that have it it doesn't work on terminal devices.  If
  2616.      we can't use select, then we do a blocked write of a single
  2617.      byte after setting an alarm.  We only write a single byte to
  2618.      avoid any confusion as to whether or not the byte was
  2619.      actually written.  */
  2620.  
  2621.       /* If we are running on standard input, we switch the file
  2622.      descriptors by hand.  */
  2623.       if (q->ord >= 0)
  2624.     q->o = q->ord;
  2625.  
  2626.       /* Do an unblocked read.  */
  2627.       if (! fsblock (q, FALSE))
  2628.     return FALSE;
  2629.  
  2630.       /* Loop until we get something (error or data) other than an
  2631.      acceptable EINTR.  */
  2632.       while (TRUE)
  2633.     {
  2634.       /* If we've received a signal, don't continue.  */
  2635.       if (FGOT_QUIT_SIGNAL ())
  2636.         return FALSE;
  2637.  
  2638. #if HAVE_TLI
  2639.       if (q->ftli)
  2640.         {
  2641.           int iflags;
  2642.  
  2643.           cgot = t_rcv (q->o, zread, cread, &iflags);
  2644.           if (cgot < 0)
  2645.         {
  2646.           if (t_errno == TNODATA)
  2647.             errno = EAGAIN;
  2648.           else if (t_errno != TSYSERR)
  2649.             {
  2650.               ulog (LOG_ERROR, "t_rcv: %s",
  2651.                 (t_errno >= 0 && t_errno < t_nerr
  2652.                  ? t_errlist[t_errno]
  2653.                  : "unknown TLI error"));
  2654.               return FALSE;
  2655.             }
  2656.         }
  2657.         }
  2658.       else
  2659. #endif
  2660.         cgot = read (q->o, zread, cread);
  2661.  
  2662.       if (cgot >= 0)
  2663.         break;
  2664.       if (errno != EINTR)
  2665.         break;
  2666.  
  2667.       /* We got interrupted by a signal.  Log it.  */
  2668.       ulog (LOG_ERROR, (const char *) NULL);
  2669.     }
  2670.  
  2671.       if (cgot < 0)
  2672.     {
  2673.       if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
  2674.         {
  2675.           ulog (LOG_ERROR, "read: %s", strerror (errno));
  2676.           return FALSE;
  2677.         }
  2678.       cgot = 0;
  2679.     }
  2680.  
  2681.       cread -= cgot;
  2682.       zread += cgot;
  2683.       *pcread += cgot;
  2684.  
  2685.       /* If we've filled the read buffer, or we have nothing left to
  2686.      write, return out.  */
  2687.       if (cread == 0 || cwrite == 0)
  2688.     return TRUE;
  2689.  
  2690.       /* The port is currently unblocked.  Do a write.  */
  2691.       cdo = cwrite;
  2692.  
  2693. #if ! HAVE_UNBLOCKED_WRITES
  2694.       if (q->fterminal && cdo > SINGLE_WRITE)
  2695.     cdo = SINGLE_WRITE;
  2696. #endif
  2697.  
  2698.       if (q->owr >= 0)
  2699.     q->o = q->owr;
  2700.  
  2701.       /* Loop until we get something besides EINTR.  */
  2702.       while (TRUE)
  2703.     {
  2704.       /* If we've received a signal, don't continue.  */
  2705.       if (FGOT_QUIT_SIGNAL ())
  2706.         return FALSE;
  2707.  
  2708. #if HAVE_TLI
  2709.       if (q->ftli)
  2710.         {
  2711.           cdid = t_snd (q->o, (char *) zwrite, cdo, 0);
  2712.           if (cdid < 0)
  2713.         {
  2714.           if (t_errno == TFLOW)
  2715.             errno = EAGAIN;
  2716.           else if (t_errno != TSYSERR)
  2717.             {
  2718.               ulog (LOG_ERROR, "t_snd: %s",
  2719.                 (t_errno >= 0 && t_errno < t_nerr
  2720.                  ? t_errlist[t_errno]
  2721.                  : "unknown TLI error"));
  2722.               return FALSE;
  2723.             }
  2724.         }
  2725.         }
  2726.       else
  2727. #endif
  2728.         cdid = write (q->o, zwrite, cdo);
  2729.  
  2730.       if (cdid >= 0)
  2731.         break;
  2732.       if (errno != EINTR)
  2733.         break;
  2734.  
  2735.       /* We got interrupted by a signal.  Log it.  */
  2736.       ulog (LOG_ERROR, (const char *) NULL);
  2737.     }
  2738.  
  2739.       if (cdid < 0)
  2740.     {
  2741.       if (errno != EAGAIN && errno != EWOULDBLOCK && errno != ENODATA)
  2742.         {
  2743.           ulog (LOG_ERROR, "write: %s", strerror (errno));
  2744.           return FALSE;
  2745.         }
  2746.       cdid = 0;
  2747.     }
  2748.  
  2749.       if (cdid > 0)
  2750.     {
  2751.       /* We wrote some data.  If we wrote everything, return out.
  2752.          Otherwise loop around and do another read.  */
  2753.       cwrite -= cdid;
  2754.       zwrite += cdid;
  2755.       *pcwrite += cdid;
  2756.  
  2757.       if (cwrite == 0)
  2758.         return TRUE;
  2759.  
  2760.       czero = 0;
  2761.     }
  2762.       else
  2763.     {
  2764. #if HAVE_SELECT
  2765.       struct timeval stime;
  2766.           long recvC;
  2767.       int imask;
  2768.       int c;
  2769.  
  2770.           /* We didn't write any data.  Call select.  We use a timeout
  2771.              long enough for recvC bytes to be received
  2772.                secs delay  == (recvC bytes * 10 bits/byte) / baud bits/sec
  2773.                usecs delay == (((recvC bytes * 1000000 usecs/sec)
  2774.                                 / baud bits/sec)
  2775.                                * 10 bits/byte)
  2776.              use recvC so we never wait for longer than 2Kb, otherwise
  2777.              we would overflow the size of a long in the usec calc.
  2778.              */
  2779.           recvC = cread; if (recvC >= 2048) recvC = 2048;
  2780.           stime.tv_sec  = recvC * 10L / (long)q->ibaud;
  2781.           stime.tv_usec = (((recvC * 1000000L / (long) q->ibaud) * 10L)
  2782.                            % 1000000L);
  2783.  
  2784.       imask = 1 << q->o;
  2785.       if (imask == 0)
  2786.         ulog (LOG_FATAL, "fsysdep_conn_io: File descriptors too large");
  2787.  
  2788.       /* If we've received a signal, don't continue.  */
  2789.       if (FGOT_QUIT_SIGNAL ())
  2790.         return FALSE;
  2791.  
  2792.       DEBUG_MESSAGE0 (DEBUG_PORT, "fsysdep_conn_io: Calling select");
  2793.  
  2794.       /* We don't bother to loop on EINTR.  If we get a signal, we
  2795.              just loop around and try the read and write again.  */
  2796.       c = select (q->o + 1, (pointer) NULL, (pointer) &imask,
  2797.               (pointer) NULL, &stime);
  2798.       if (c < 0 && errno == EINTR)
  2799.         {
  2800.           /* We got interrupted by a signal.  Log it.  */
  2801.           ulog (LOG_ERROR, (const char *) NULL);
  2802.         }
  2803.       else if (c >= 0)
  2804.         {
  2805.           /* The select either discovered that we could write
  2806.                  something, or it timed out.  Either way, we go around
  2807.                  the main read/write loop again.  */
  2808.         }
  2809.       else
  2810. #endif /* HAVE_SELECT */
  2811.         {
  2812.           int ierr;
  2813.  
  2814.           /* Either the select failed for some reason other than
  2815.                EINTR, or the system does not support select at all.
  2816.                Fall back on a timed write.  We don't worry about why
  2817.                the select might have failed, we just assume that it
  2818.                will not succeed on this descriptor.  */
  2819.  
  2820. #if HAVE_RESTARTABLE_SYSCALLS
  2821.           /* If HAVE_RESTARTABLE_SYSCALLS, then receiving an alarm
  2822.                  signal in the middle of a write will not cause the
  2823.                  write to return EINTR, and the only way to interrupt
  2824.                  the write is to longjmp out of it (see sysh.unx).
  2825.                  That is unreliable, because it means that we won't
  2826.                  know whether the byte was actually written or not.
  2827.                  However, I believe that the only system on which we
  2828.                  need to do this longjmp is BSD 4.2, and that system
  2829.                  supports select, so we should never execute this
  2830.                  case.  */
  2831.           ulog (LOG_FATAL, "fsysdep_conn_io: Unsupported case; see code");
  2832. #endif
  2833.  
  2834.           if (q->ord >= 0)
  2835.         q->o = q->ord;
  2836.  
  2837.           if (! fsblock (q, TRUE))
  2838.         return FALSE;
  2839.  
  2840.           DEBUG_MESSAGE0 (DEBUG_PORT, "fsysdep_conn_io: Blocking write");
  2841.  
  2842.           if (q->owr >= 0)
  2843.         q->o = q->owr;
  2844.  
  2845.           /* If we've received a signal, don't continue.  */
  2846.           if (FGOT_QUIT_SIGNAL ())
  2847.         return FALSE;
  2848.  
  2849.           /* Start up an alarm to interrupt the write.  Note that
  2850.                  we don't need to use the catch stuff, since we know
  2851.                  that HAVE_RESTARTABLE_SYSCALLS is 0.  */
  2852.           usset_signal (SIGALRM, usalarm, TRUE, (boolean *) NULL);
  2853.           alarm ((int) ((long) 10240 / q->ibaud) + 1);
  2854.  
  2855.           /* There is a race condition here: on a severely loaded
  2856.                  system, we could get the alarm before we start the
  2857.                  write call.  This would not be a disaster; often the
  2858.                  write will succeed anyhow.  */
  2859. #if HAVE_TLI
  2860.           if (q->ftli)
  2861.         {
  2862.           cdid = t_snd (q->o, (char *) zwrite, 1, 0);
  2863.           if (cdid < 0 && t_errno != TSYSERR)
  2864.             {
  2865.               usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2866.               alarm (0);
  2867.               ulog (LOG_ERROR, "t_snd: %s",
  2868.                 (t_errno >= 0 && t_errno < t_nerr
  2869.                  ? t_errlist[t_errno]
  2870.                  : "unknown TLI error"));
  2871.               return FALSE;
  2872.             }
  2873.         }
  2874.           else
  2875. #endif
  2876.         cdid = write (q->o, zwrite, 1);
  2877.  
  2878.           ierr = errno;
  2879.  
  2880.           /* Note that we don't really care whether the write
  2881.                  finished because the byte was written out or whether
  2882.                  it finished because the alarm was triggered.  Either
  2883.                  way, we are going to loop around and try another
  2884.                  read.  */
  2885.  
  2886.           usset_signal (SIGALRM, SIG_IGN, TRUE, (boolean *) NULL);
  2887.           alarm (0);
  2888.  
  2889.           if (cdid < 0)
  2890.         {
  2891.           if (ierr == EINTR)
  2892.             {
  2893.               /* We got interrupted by a signal.  Log it.  */
  2894.               ulog (LOG_ERROR, (const char *) NULL);
  2895.             }
  2896.           else
  2897.             {
  2898.               ulog (LOG_ERROR, "write: %s", strerror (ierr));
  2899.               return FALSE;
  2900.             }
  2901.         }
  2902.           else if (cdid == 0)
  2903.         {
  2904.           /* On some systems write will return 0 if carrier is
  2905.              lost.  If we fail to write anything ten times in
  2906.              a row, we assume that this has happened.  This is
  2907.              hacked in like this because there seems to be no
  2908.              reliable way to tell exactly why the write
  2909.              returned 0.  */
  2910.           ++czero;
  2911.           if (czero >= 10)
  2912.             {
  2913.               ulog (LOG_ERROR, "Line disconnected");
  2914.               return FALSE;
  2915.             }
  2916.         }
  2917.           else
  2918.         {
  2919.           cwrite -= cdid;
  2920.           zwrite += cdid;
  2921.           *pcwrite += cdid;
  2922.           czero = 0;
  2923.         }
  2924.         }
  2925.     }
  2926.     }
  2927. }
  2928.  
  2929. /* Send a break character to a serial port.  */
  2930.  
  2931. static boolean
  2932. fsserial_break (qconn)
  2933.      struct sconnection *qconn;
  2934. {
  2935.   struct ssysdep_conn *q;
  2936.  
  2937.   q = (struct ssysdep_conn *) qconn->psysdep;
  2938.  
  2939. #if HAVE_BSD_TTY
  2940.   (void) ioctl (q->o, TIOCSBRK, 0);
  2941.   sleep (2);
  2942.   (void) ioctl (q->o, TIOCCBRK, 0);
  2943.   return TRUE;
  2944. #endif /* HAVE_BSD_TTY */
  2945. #if HAVE_SYSV_TERMIO
  2946.   (void) ioctl (q->o, TCSBRK, 0);
  2947.   return TRUE;
  2948. #endif /* HAVE_SYSV_TERMIO */
  2949. #if HAVE_POSIX_TERMIOS
  2950.   return tcsendbreak (q->o, 0) == 0;
  2951. #endif /* HAVE_POSIX_TERMIOS */
  2952. }
  2953.  
  2954. /* Send a break character to a stdin port.  */
  2955.  
  2956. static boolean
  2957. fsstdin_break (qconn)
  2958.      struct sconnection *qconn;
  2959. {
  2960.   struct ssysdep_conn *qsysdep;
  2961.  
  2962.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  2963.   qsysdep->o = qsysdep->owr;
  2964.   return fsserial_break (qconn);
  2965. }
  2966.  
  2967. /* Change the setting of a serial port.  */
  2968.  
  2969. /*ARGSUSED*/
  2970. static boolean
  2971. fsserial_set (qconn, tparity, tstrip, txonxoff)
  2972.      struct sconnection *qconn;
  2973.      enum tparitysetting tparity;
  2974.      enum tstripsetting tstrip;
  2975.      enum txonxoffsetting txonxoff;
  2976. {
  2977.   register struct ssysdep_conn *q;
  2978.   boolean fchanged, fdo;
  2979.   int iset = 0;
  2980.   int iclear = 0;
  2981.  
  2982.   q = (struct ssysdep_conn *) qconn->psysdep;
  2983.  
  2984.   if (! q->fterminal)
  2985.     return TRUE;
  2986.  
  2987.   fchanged = FALSE;
  2988.  
  2989.   /* Set the parity for output characters.  */
  2990.  
  2991. #if HAVE_BSD_TTY
  2992.  
  2993.   /* This will also cause parity detection on input characters.  */
  2994.  
  2995.   fdo = FALSE;
  2996.   switch (tparity)
  2997.     {
  2998.     case PARITYSETTING_DEFAULT:
  2999.       break;
  3000.     case PARITYSETTING_NONE:
  3001. #if HAVE_PARITY_BUG
  3002.       /* The Sony NEWS mishandles this for some reason.  */
  3003.       iset = 0;
  3004.       iclear = ANYP;
  3005. #else
  3006.       iset = ANYP;
  3007.       iclear = 0;
  3008. #endif
  3009.       fdo = TRUE;
  3010.       break;
  3011.     case PARITYSETTING_EVEN:
  3012.       iset = EVENP;
  3013.       iclear = ODDP;
  3014.       fdo = TRUE;
  3015.       break;
  3016.     case PARITYSETTING_ODD:
  3017.       iset = ODDP;
  3018.       iclear = EVENP;
  3019.       fdo = TRUE;
  3020.       break;
  3021.     case PARITYSETTING_MARK:
  3022.     case PARITYSETTING_SPACE:
  3023.       /* Not supported.  */
  3024.       break;
  3025.     }
  3026.  
  3027.   if (fdo)
  3028.     {
  3029.       if ((q->snew.stty.sg_flags & iset) != iset
  3030.       || (q->snew.stty.sg_flags & iclear) != 0)
  3031.     {
  3032.       q->snew.stty.sg_flags |= iset;
  3033.       q->snew.stty.sg_flags &=~ iclear;
  3034.       fchanged = TRUE;
  3035.     }
  3036.     }
  3037.  
  3038. #else /* ! HAVE_BSD_TTY */
  3039.  
  3040.   fdo = FALSE;
  3041.   switch (tparity)
  3042.     {
  3043.     case PARITYSETTING_DEFAULT:
  3044.       break;
  3045.     case PARITYSETTING_NONE:
  3046.       iset = CS8;
  3047.       iclear = PARENB | PARODD | (CSIZE &~ CS8);
  3048.       fdo = TRUE;
  3049.       break;
  3050.     case PARITYSETTING_EVEN:
  3051.       iset = PARENB | CS7;
  3052.       iclear = PARODD | (CSIZE &~ CS7);
  3053.       fdo = TRUE;
  3054.       break;
  3055.     case PARITYSETTING_ODD:
  3056.       iset = PARENB | PARODD | CS7;
  3057.       iclear = CSIZE &~ CS7;
  3058.       fdo = TRUE;
  3059.       break;
  3060.     case PARITYSETTING_MARK:
  3061.     case PARITYSETTING_SPACE:
  3062.       /* Not supported.  */
  3063.       break;
  3064.     }
  3065.       
  3066.   if (fdo)
  3067.     {
  3068.       if ((q->snew.c_cflag & iset) != iset
  3069.       || (q->snew.c_cflag & iclear) != 0)
  3070.     {
  3071.       q->snew.c_cflag |= iset;
  3072.       q->snew.c_cflag &=~ iclear;
  3073.       fchanged = TRUE;
  3074.     }
  3075.     }
  3076.  
  3077. #endif /* ! HAVE_BSD_TTY */
  3078.  
  3079.   /* Set whether input characters are stripped to seven bits.  */
  3080.  
  3081. #if HAVE_BSD_TTY
  3082.  
  3083. #ifdef LPASS8
  3084.   {
  3085.     int i;
  3086.  
  3087.     i = LPASS8;
  3088.     if (tstrip == STRIPSETTING_EIGHTBITS)
  3089.       {
  3090.     i = LPASS8;
  3091.     (void) ioctl (q->o, TIOCLBIS, &i);
  3092.       }
  3093.     else if (tstrip == STRIPSETTING_SEVENBITS)
  3094.       {
  3095.     i = LPASS8;
  3096.     (void) ioctl (q->o, TIOCLBIC, &i);
  3097.       }
  3098.   }
  3099. #endif
  3100.  
  3101. #else /* ! HAVE_BSD_TTY */      
  3102.  
  3103.   fdo = FALSE;
  3104.   switch (tstrip)
  3105.     {
  3106.     case STRIPSETTING_DEFAULT:
  3107.       break;
  3108.     case STRIPSETTING_EIGHTBITS:
  3109.       iset = 0;
  3110.       iclear = ISTRIP;
  3111.       fdo = TRUE;
  3112.       break;
  3113.     case STRIPSETTING_SEVENBITS:
  3114.       iset = ISTRIP;
  3115.       iclear = 0;
  3116.       fdo = TRUE;
  3117.       break;
  3118.     }
  3119.  
  3120.   if (fdo)
  3121.     {
  3122.       if ((q->snew.c_iflag & iset) != iset
  3123.       || (q->snew.c_iflag & iclear) != 0)
  3124.     {
  3125.       q->snew.c_iflag |= iset;
  3126.       q->snew.c_iflag &=~ iclear;
  3127.       fchanged = TRUE;
  3128.     }
  3129.     }
  3130.  
  3131. #endif /* ! HAVE_BSD_TTY */
  3132.  
  3133.   /* Set XON/XOFF handshaking.  */
  3134.  
  3135. #if HAVE_BSD_TTY
  3136.  
  3137.   fdo = FALSE;
  3138.   switch (txonxoff)
  3139.     {
  3140.     case XONXOFF_DEFAULT:
  3141.       break;
  3142.     case XONXOFF_OFF:
  3143.       iset = RAW;
  3144.       iclear = TANDEM | CBREAK;
  3145.       fdo = TRUE;
  3146.       break;
  3147.     case XONXOFF_ON:
  3148.       iset = CBREAK | TANDEM;
  3149.       iclear = RAW;
  3150.       fdo = TRUE;
  3151.       break;
  3152.     }
  3153.  
  3154.   if (fdo)
  3155.     {
  3156.       if ((q->snew.stty.sg_flags & iset) != iset
  3157.       || (q->snew.stty.sg_flags & iclear) != 0)
  3158.     {
  3159.       q->snew.stty.sg_flags |= iset;
  3160.       q->snew.stty.sg_flags &=~ iclear;
  3161.       fchanged = TRUE;
  3162.     }
  3163.     }
  3164.  
  3165. #else /* ! HAVE_BSD_TTY */
  3166.  
  3167.   fdo = FALSE;
  3168.   switch (txonxoff)
  3169.     {
  3170.     case XONXOFF_DEFAULT:
  3171.       break;
  3172.     case XONXOFF_OFF:
  3173.       iset = 0;
  3174.       iclear = IXON | IXOFF;
  3175.       fdo = TRUE;
  3176.       break;
  3177.     case XONXOFF_ON:
  3178. #ifdef CRTSCTS
  3179. #if HAVE_POSIX_TERMIOS
  3180.       /* This is system dependent, but I haven't figured out a good
  3181.      way around it yet.  If we are doing hardware flow control, we
  3182.      don't send XON/XOFF characters but we do recognize them.  */
  3183.       if ((q->snew.c_cflag & CRTSCTS) != 0)
  3184.     {
  3185.       iset = IXON;
  3186.       iclear = IXOFF;
  3187.       fdo = TRUE;
  3188.       break;
  3189.     }
  3190. #endif /* HAVE_POSIX_TERMIOS */
  3191. #endif /* defined (CRTSCTS) */
  3192. #ifdef CRTSFL
  3193.       if ((q->snew.c_cflag & CRTSFL) != 0)
  3194.     {
  3195.       iset = IXON;
  3196.       iclear = IXOFF;
  3197.       /* SCO says we cant have CRTSFL **and** RTSFLOW/CTSFLOW */
  3198. #ifdef RTSFLOW
  3199.       iclear |= RTSFLOW;
  3200. #endif
  3201. #ifdef CTSFLOW
  3202.       iclear |= CTSFLOW;
  3203. #endif
  3204.       fdo = TRUE;
  3205.       break;
  3206.     }
  3207. #endif /* defined(CRTSFL) */
  3208.       iset = IXON | IXOFF;
  3209.       iclear = 0;
  3210.       fdo = TRUE;
  3211.       break;
  3212.     }
  3213.  
  3214.   if (fdo)
  3215.     {
  3216.       if ((q->snew.c_iflag & iset) != iset
  3217.       || (q->snew.c_iflag & iclear) != 0)
  3218.     {
  3219.       q->snew.c_iflag |= iset;
  3220.       q->snew.c_iflag &=~ iclear;
  3221.       fchanged = TRUE;
  3222.     }
  3223.     }
  3224.  
  3225. #endif /* ! HAVE_BSD_TTY */
  3226.  
  3227.   if (fchanged)
  3228.     {
  3229.       if (! fsetterminfodrain (q->o, &q->snew))
  3230.     {
  3231.       ulog (LOG_ERROR, "Can't change terminal settings: %s",
  3232.         strerror (errno));
  3233.       return FALSE;
  3234.     }
  3235.     }
  3236.  
  3237. #if HAVE_BSD_TTY
  3238.   if (txonxoff == XONXOFF_ON
  3239.       && (q->snew.stty.sg_flags & ANYP) == ANYP)
  3240.     {
  3241.       int i;
  3242.  
  3243.       /* At least on Ultrix, we seem to have to set LLITOUT and
  3244.      LPASS8.  This shouldn't foul things up anywhere else.  As far
  3245.      as I can tell, this has to be done after setting the terminal
  3246.      into cbreak mode, not before.  */
  3247. #ifndef LLITOUT
  3248. #define LLITOUT 0
  3249. #endif
  3250. #ifndef LPASS8
  3251. #define LPASS8 0
  3252. #endif
  3253. #ifndef LAUTOFLOW
  3254. #define LAUTOFLOW 0
  3255. #endif
  3256.       i = LLITOUT | LPASS8 | LAUTOFLOW;
  3257.       (void) ioctl (q->o, TIOCLBIS, &i);
  3258.  
  3259. #if HAVE_STRIP_BUG
  3260.       /* Ultrix 4.0 has a peculiar problem: setting CBREAK always
  3261.      causes input characters to be stripped.  I hope this does not
  3262.      apply to other BSD systems.  It is possible to work around
  3263.      this by using the termio call.  I wish this sort of stuff was
  3264.      not necessary!!!  */
  3265.       {
  3266.     struct termio s;
  3267.  
  3268.     if (ioctl (q->o, TCGETA, &s) >= 0)
  3269.       {
  3270.         s.c_iflag &=~ ISTRIP;
  3271.         (void) ioctl (q->o, TCSETA, &s);
  3272.       }
  3273.       }
  3274. #endif /* HAVE_STRIP_BUG */
  3275.     }
  3276. #endif /* HAVE_BSD_TTY */
  3277.  
  3278.   return TRUE;
  3279. }
  3280.  
  3281. /* Change settings of a stdin port.  */
  3282.  
  3283. static boolean
  3284. fsstdin_set (qconn, tparity, tstrip, txonxoff)
  3285.      struct sconnection *qconn;
  3286.      enum tparitysetting tparity;
  3287.      enum tstripsetting tstrip;
  3288.      enum txonxoffsetting txonxoff;
  3289. {
  3290.   struct ssysdep_conn *qsysdep;
  3291.  
  3292.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  3293.   qsysdep->o = qsysdep->ord;
  3294.   return fsserial_set (qconn, tparity, tstrip, txonxoff);
  3295. }
  3296.  
  3297. /* Run a chat program.  */
  3298.  
  3299. static boolean
  3300. fsrun_chat (oread, owrite, pzprog)
  3301.      int oread;
  3302.      int owrite;
  3303.      char **pzprog;
  3304. {
  3305.   int aidescs[3];
  3306.   FILE *e;
  3307.   pid_t ipid;
  3308.   char *z;
  3309.   size_t c;
  3310.  
  3311.   aidescs[0] = oread;
  3312.   aidescs[1] = owrite;
  3313.   aidescs[2] = SPAWN_READ_PIPE;
  3314.  
  3315.   /* Pass fkeepuid, fkeepenv and fshell as TRUE.  This puts the
  3316.      responsibility of maintaing security on the chat program.  */
  3317.   ipid = ixsspawn ((const char **) pzprog, aidescs, TRUE, TRUE,
  3318.            (const char *) NULL, FALSE, TRUE, (const char *) NULL,
  3319.            (const char *) NULL, (const char *) NULL);
  3320.   if (ipid < 0)
  3321.     {
  3322.       ulog (LOG_ERROR, "ixsspawn (%s): %s", pzprog[0], strerror (errno));
  3323.       return FALSE;
  3324.     }
  3325.  
  3326.   e = fdopen (aidescs[2], (char *) "r");
  3327.   if (e == NULL)
  3328.     {
  3329.       ulog (LOG_ERROR, "fdopen: %s", strerror (errno));
  3330.       (void) close (aidescs[2]);
  3331.       (void) kill (ipid, SIGKILL);
  3332.       (void) ixswait ((unsigned long) ipid, (const char *) NULL);
  3333.       return FALSE;
  3334.     }
  3335.  
  3336.   /* The FILE e now is attached to stderr of the program.  Forward
  3337.      every line the program outputs to the log file.  */
  3338.   z = NULL;
  3339.   c = 0;
  3340.   while (getline (&z, &c, e) > 0)
  3341.     {
  3342.       size_t clen;
  3343.  
  3344.       clen = strlen (z);
  3345.       if (z[clen - 1] == '\n')
  3346.     z[clen - 1] = '\0';
  3347.       if (*z != '\0')
  3348.     ulog (LOG_NORMAL, "chat: %s", z);
  3349.     }
  3350.  
  3351.   xfree ((pointer) z);
  3352.   (void) fclose (e);
  3353.  
  3354.   return ixswait ((unsigned long) ipid, "Chat program") == 0;
  3355. }
  3356.  
  3357. /* Run a chat program on a port using separate read/write file
  3358.    descriptors.  */
  3359.  
  3360. boolean
  3361. fsdouble_chat (qconn, pzprog)
  3362.      struct sconnection *qconn;
  3363.      char **pzprog;
  3364. {
  3365.   struct ssysdep_conn *qsysdep;
  3366.   boolean fret;
  3367.  
  3368.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  3369.   fret = fsrun_chat (qsysdep->ord, qsysdep->owr, pzprog);
  3370.   if (qsysdep->fterminal)
  3371.     (void) fgetterminfo (qsysdep->ord, &qsysdep->snew);
  3372.   return fret;
  3373. }
  3374.  
  3375. /* Run a chat program on any general type of connection.  */
  3376.  
  3377. boolean
  3378. fsysdep_conn_chat (qconn, pzprog)
  3379.      struct sconnection *qconn;
  3380.      char **pzprog;
  3381. {
  3382.   struct ssysdep_conn *qsysdep;
  3383.   boolean fret;
  3384.  
  3385.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  3386.   fret = fsrun_chat (qsysdep->o, qsysdep->o, pzprog);
  3387.   if (qsysdep->fterminal)
  3388.     (void) fgetterminfo (qsysdep->o, &qsysdep->snew);
  3389.   return fret;
  3390. }
  3391.  
  3392. /* Return baud rate of a serial port.  */
  3393.  
  3394. static long
  3395. isserial_baud (qconn)
  3396.      struct sconnection *qconn;
  3397. {
  3398.   struct ssysdep_conn *qsysdep;
  3399.  
  3400.   qsysdep = (struct ssysdep_conn *) qconn->psysdep;
  3401.   return qsysdep->ibaud;
  3402. }
  3403.